@scemoon/cdh 1.0.4 → 1.0.6
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.
- package/ai-dlc-skill/SKILL.md +4 -2
- package/ai-dlc-skill/agents/master.md +6 -0
- package/ai-dlc-skill/agents/plan-agent.md +2 -2
- package/ai-dlc-skill/agents/understand-agent.md +4 -4
- package/ai-dlc-skill/agents/verify-agent.md +1 -1
- package/ai-dlc-skill/architecture/project-structure.md +10 -10
- package/ai-dlc-skill/brownfield/README.md +2 -2
- package/ai-dlc-skill/brownfield/generate-context.sh +3 -3
- package/ai-dlc-skill/brownfield/scripts/extract-api.sh +5 -5
- package/ai-dlc-skill/components/backend.md +1 -1
- package/ai-dlc-skill/components/web.md +2 -2
- package/ai-dlc-skill/contracts/README.md +3 -3
- package/ai-dlc-skill/cross-tool/cline/export.sh +1 -1
- package/ai-dlc-skill/cross-tool/copilot/export.sh +1 -1
- package/ai-dlc-skill/cross-tool/onecode/export-skills.sh +7 -3
- package/ai-dlc-skill/cross-tool/onecode/export.sh +14 -8
- package/ai-dlc-skill/phases/deliver/lifecycle.md +6 -6
- package/ai-dlc-skill/phases/deliver/prompt.md +2 -2
- package/ai-dlc-skill/phases/deliver/rules.md +1 -1
- package/ai-dlc-skill/phases/plan/lifecycle.md +11 -11
- package/ai-dlc-skill/phases/plan/prompt.md +6 -6
- package/ai-dlc-skill/phases/plan/rules.md +1 -1
- package/ai-dlc-skill/phases/understand/entry.md +1 -1
- package/ai-dlc-skill/phases/understand/lifecycle.md +7 -7
- package/ai-dlc-skill/phases/understand/prompt.md +8 -8
- package/ai-dlc-skill/phases/understand/rules.md +5 -5
- package/ai-dlc-skill/phases/verify/lifecycle.md +24 -24
- package/ai-dlc-skill/phases/verify/prompt.md +8 -8
- package/ai-dlc-skill/phases/verify/rules.md +9 -9
- package/ai-dlc-skill/providers/README.md +2 -2
- package/ai-dlc-skill/providers/aliyun/preview.yaml +2 -2
- package/ai-dlc-skill/providers/tcb/preview.yaml +2 -2
- package/ai-dlc-skill/requirements.md +7 -7
- package/ai-dlc-skill/skill.yaml +4 -4
- package/ai-dlc-skill/templates/integration/CHANGELOG.md +2 -2
- package/ai-dlc-skill/templates/integration/contract-diff.md +7 -7
- package/ai-dlc-skill/templates/integration/contract-spec.md +7 -7
- package/ai-dlc-skill/templates/integration/runtime-contract.yaml +1 -1
- package/ai-dlc-skill/templates/project/README.md +18 -19
- package/ai-dlc-skill/templates/project/template.md +21 -21
- package/ai-dlc-skill/walkthrough/collect.sh +1 -1
- package/ai-dlc-skill/walkthrough/template.md +2 -2
- package/ai-dlc-skill/workflows/ai-dlc.yaml +12 -12
- package/ai-dlc-skill/workflows/deployment.yaml +4 -4
- package/cdh/__pycache__/cdh_mcp_injector.cpython-314.pyc +0 -0
- package/cdh/__pycache__/cdh_mcp_loader.cpython-314.pyc +0 -0
- package/cdh/__pycache__/cdh_mcp_manager.cpython-314.pyc +0 -0
- package/cdh/__pycache__/cdh_session_aggregator.cpython-314.pyc +0 -0
- package/cdh/__pycache__/cdh_skill_loader.cpython-314.pyc +0 -0
- package/cdh/__pycache__/cdh_skill_manager.cpython-314.pyc +0 -0
- package/cdh/__pycache__/cli.cpython-313.pyc +0 -0
- package/cdh/__pycache__/cli.cpython-314.pyc +0 -0
- package/cdh/__pycache__/scaffold.cpython-314.pyc +0 -0
- package/cdh/cdh_mcp_injector.py +115 -0
- package/cdh/cdh_mcp_loader.py +67 -0
- package/cdh/cdh_mcp_manager.py +73 -0
- package/cdh/cdh_session_aggregator.py +258 -0
- package/cdh/cdh_skill_manager.py +105 -0
- package/cdh/cli.py +64 -4
- package/cdh/scaffold.py +192 -41
- package/onecode/__init__.py +1 -1
- package/onecode/__pycache__/cli.cpython-314.pyc +0 -0
- package/onecode/__pycache__/commands.cpython-314.pyc +0 -0
- package/onecode/__pycache__/config.cpython-314.pyc +0 -0
- package/onecode/__pycache__/config_screen.cpython-314.pyc +0 -0
- package/onecode/__pycache__/migrate.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/cdh_loader.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/context.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/engine.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/hooks.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/onecode_agent_acp.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/permissions.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/project_doc.cpython-314.pyc +0 -0
- package/onecode/agent/__pycache__/session.cpython-314.pyc +0 -0
- package/onecode/agent/agents/__pycache__/types.cpython-314.pyc +0 -0
- package/onecode/agent/agents/types.py +47 -164
- package/onecode/agent/attachments.py +0 -1
- package/onecode/agent/cdh_loader.py +17 -25
- package/onecode/agent/context.py +8 -3
- package/onecode/agent/engine.py +835 -220
- package/onecode/agent/hooks.py +1 -1
- package/onecode/agent/onecode_agent_acp.py +460 -47
- package/onecode/agent/onecode_agent_acp.py.bak +2447 -0
- package/onecode/agent/permissions.py +0 -1
- package/onecode/agent/project_doc.py +19 -0
- package/onecode/agent/session.py +17 -3
- package/onecode/agent/snapshot.py +3 -4
- package/onecode/agent/tools/__pycache__/agent_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/apply_patch_tool.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/bash_tool.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/communication_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/config_tool.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/cron_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/file_ops.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/file_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/git_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/lsp_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/mcp_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/permission_handler.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/protocol.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/registry.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/sandbox.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/skill_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/todo_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/__pycache__/web_tools.cpython-314.pyc +0 -0
- package/onecode/agent/tools/agent_tools.py +4 -6
- package/onecode/agent/tools/apply_patch_tool.py +2 -8
- package/onecode/agent/tools/bash_tool.py +32 -12
- package/onecode/agent/tools/communication_tools.py +4 -5
- package/onecode/agent/tools/config_tool.py +3 -3
- package/onecode/agent/tools/cron_tools.py +4 -5
- package/onecode/agent/tools/file_ops.py +37 -3
- package/onecode/agent/tools/file_tools.py +10 -11
- package/onecode/agent/tools/git_tools.py +2 -2
- package/onecode/agent/tools/lsp_tools.py +2 -2
- package/onecode/agent/tools/mcp_tools.py +3 -5
- package/onecode/agent/tools/permission_handler.py +1 -1
- package/onecode/agent/tools/protocol.py +1 -1
- package/onecode/agent/tools/registry.py +69 -2
- package/onecode/agent/tools/sandbox.py +110 -16
- package/onecode/agent/tools/skill_tools.py +2 -2
- package/onecode/agent/tools/todo_tools.py +38 -19
- package/onecode/agent/tools/web_tools.py +6 -7
- package/onecode/builtin_skills/agent-browser/SKILL.md +212 -0
- package/onecode/builtin_skills/agent-browser/skill.yaml +8 -0
- package/onecode/builtin_skills/skill-creator/SKILL.md +106 -0
- package/onecode/builtin_skills/skill-creator/skill.yaml +8 -0
- package/onecode/cli.py +186 -6
- package/onecode/codebase/__pycache__/chunker.cpython-314.pyc +0 -0
- package/onecode/codebase/__pycache__/indexer.cpython-314.pyc +0 -0
- package/onecode/codebase/__pycache__/retriever.cpython-314.pyc +0 -0
- package/onecode/codebase/__pycache__/storage.cpython-314.pyc +0 -0
- package/onecode/codebase/chunker.py +0 -5
- package/onecode/codebase/indexer.py +14 -1
- package/onecode/codebase/retriever.py +13 -2
- package/onecode/codebase/storage.py +5 -4
- package/onecode/commands.py +81 -6
- package/onecode/config.py +41 -12
- package/onecode/config_screen.py +7 -3
- package/onecode/mcp/__pycache__/manager.cpython-314.pyc +0 -0
- package/onecode/mcp/manager.py +2 -3
- package/onecode/memory/__init__.py +7 -53
- package/onecode/memory/__pycache__/__init__.cpython-314.pyc +0 -0
- package/onecode/memory/__pycache__/backend.cpython-314.pyc +0 -0
- package/onecode/memory/__pycache__/offload.cpython-314.pyc +0 -0
- package/onecode/memory/__pycache__/pyramid.cpython-314.pyc +0 -0
- package/onecode/memory/__pycache__/recall.cpython-314.pyc +0 -0
- package/onecode/memory/backend.py +13 -39
- package/onecode/memory/pyramid.py +2 -71
- package/onecode/memory/recall.py +38 -3
- package/onecode/migrate.py +122 -0
- package/onecode/models/__pycache__/messages.cpython-314.pyc +0 -0
- package/onecode/models/__pycache__/provider.cpython-314.pyc +0 -0
- package/onecode/models/messages.py +58 -0
- package/onecode/models/provider.py +20 -2
- package/onecode/models/providers/__pycache__/anthropic_provider.cpython-314.pyc +0 -0
- package/onecode/models/providers/__pycache__/glm_provider.cpython-314.pyc +0 -0
- package/onecode/models/providers/__pycache__/minimax_provider.cpython-314.pyc +0 -0
- package/onecode/models/providers/__pycache__/minimaxi_provider.cpython-314.pyc +0 -0
- package/onecode/models/providers/__pycache__/ollama_provider.cpython-314.pyc +0 -0
- package/onecode/models/providers/anthropic_provider.py +59 -12
- package/onecode/models/providers/glm_provider.py +40 -0
- package/onecode/models/providers/minimax_provider.py +3 -0
- package/onecode/models/providers/minimaxi_provider.py +3 -0
- package/onecode/models/providers/ollama_provider.py +3 -0
- package/onecode/server/app.py +1 -1
- package/onecode/skills/__pycache__/argument_substitution.cpython-314.pyc +0 -0
- package/onecode/skills/__pycache__/bootstrap.cpython-314.pyc +0 -0
- package/onecode/skills/__pycache__/loader.cpython-314.pyc +0 -0
- package/onecode/skills/__pycache__/manager.cpython-314.pyc +0 -0
- package/onecode/skills/argument_substitution.py +0 -1
- package/onecode/skills/bootstrap.py +124 -0
- package/onecode/skills/loader.py +35 -53
- package/onecode/skills/manager.py +2 -2
- package/onecode/storage/activity.py +3 -4
- package/onecode/storage/session.py +3 -4
- package/onecode/tasks/manager.py +23 -10
- package/onecode/trace/tracer.py +2 -3
- package/package.json +1 -1
- package/pyproject.toml +5 -1
- package/run.js +68 -14
- package/tui/__pycache__/about.cpython-314.pyc +0 -0
- package/tui/__pycache__/app.cpython-313.pyc +0 -0
- package/tui/__pycache__/app.cpython-314.pyc +0 -0
- package/tui/__pycache__/danger.cpython-314.pyc +0 -0
- package/tui/__pycache__/directory_suggester.cpython-314.pyc +0 -0
- package/tui/__pycache__/messages.cpython-314.pyc +0 -0
- package/tui/__pycache__/path_complete.cpython-314.pyc +0 -0
- package/tui/__pycache__/paths.cpython-314.pyc +0 -0
- package/tui/__pycache__/session_tracker.cpython-314.pyc +0 -0
- package/tui/__pycache__/settings_schema.cpython-314.pyc +0 -0
- package/tui/acp/__pycache__/agent.cpython-314.pyc +0 -0
- package/tui/acp/__pycache__/api.cpython-314.pyc +0 -0
- package/tui/acp/__pycache__/messages.cpython-314.pyc +0 -0
- package/tui/acp/__pycache__/prompt.cpython-314.pyc +0 -0
- package/tui/acp/__pycache__/protocol.cpython-314.pyc +0 -0
- package/tui/acp/agent.py +125 -58
- package/tui/acp/api.py +12 -0
- package/tui/acp/messages.py +3 -1
- package/tui/acp/prompt.py +0 -57
- package/tui/acp/protocol.py +6 -0
- package/tui/app.py +11 -33
- package/tui/messages.py +2 -0
- package/tui/path_complete.py +1 -1
- package/tui/paths.py +16 -0
- package/tui/screens/__pycache__/agent_modal.cpython-314.pyc +0 -0
- package/tui/screens/__pycache__/component_picker.cpython-314.pyc +0 -0
- package/tui/screens/__pycache__/diff_screen.cpython-314.pyc +0 -0
- package/tui/screens/__pycache__/log.cpython-314.pyc +0 -0
- package/tui/screens/__pycache__/main.cpython-313.pyc +0 -0
- package/tui/screens/__pycache__/main.cpython-314.pyc +0 -0
- package/tui/screens/__pycache__/permissions.cpython-314.pyc +0 -0
- package/tui/screens/__pycache__/projects_app.cpython-314.pyc +0 -0
- package/tui/screens/__pycache__/projects_screen.cpython-314.pyc +0 -0
- package/tui/screens/__pycache__/sessions.cpython-314.pyc +0 -0
- package/tui/screens/__pycache__/store.cpython-314.pyc +0 -0
- package/tui/screens/__pycache__/tool_content_screen.cpython-314.pyc +0 -0
- package/tui/screens/component_picker.py +35 -15
- package/tui/screens/diff_screen.py +84 -0
- package/tui/screens/log.py +25 -25
- package/tui/screens/main.py +48 -26
- package/tui/screens/projects.tcss +5 -1
- package/tui/screens/projects_app.py +6 -6
- package/tui/screens/projects_screen.py +19 -39
- package/tui/screens/sessions.py +3 -5
- package/tui/session_tracker.py +3 -0
- package/tui/settings_schema.py +1 -1
- package/tui/visuals/__pycache__/columns.cpython-314.pyc +0 -0
- package/tui/visuals/columns.py +1 -2
- package/tui/widgets/__pycache__/acp_content.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/agent_response.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/agent_thought.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/conversation.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/diff_view.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/directory_input.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/future_text.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/grid_select.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/load_more.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/mandelbrot.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/markdown_note.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/modified_files.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/plan.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/project_grid_select.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/project_summary.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/session_grid_select.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/session_summary.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/shell_result.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/side_bar.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/subagent.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/subagent_screen.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/terminal.cpython-314.pyc +0 -0
- package/tui/widgets/__pycache__/tool_call.cpython-314.pyc +0 -0
- package/tui/widgets/agent_response.py +0 -1
- package/tui/widgets/agent_thought.py +0 -1
- package/tui/widgets/conversation.py +157 -14
- package/tui/widgets/diff_view.py +10 -0
- package/tui/widgets/load_more.py +24 -0
- package/tui/widgets/modified_files.py +86 -12
- package/tui/widgets/plan.py +1 -1
- package/tui/widgets/project_grid_select.py +9 -2
- package/tui/widgets/session_grid_select.py +6 -0
- package/tui/widgets/side_bar.py +10 -0
- package/tui/widgets/subagent.py +92 -58
- package/tui/widgets/subagent_screen.py +638 -115
- package/tui/widgets/terminal.py +1 -2
- package/tui/widgets/terminal_tool.py +11 -2
- package/tui/widgets/tool_call.py +35 -2
- package/onecode/memory/offload.py +0 -114
- package/onecode/memory/symbolic.py +0 -164
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: skill-creator
|
|
3
|
+
description: Guide for creating new agent skills with proper conventions
|
|
4
|
+
enabled: true
|
|
5
|
+
triggers:
|
|
6
|
+
- create skill
|
|
7
|
+
- new skill
|
|
8
|
+
- scaffold skill
|
|
9
|
+
- write skill
|
|
10
|
+
- make a skill
|
|
11
|
+
- build a skill
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Skill Creator
|
|
15
|
+
|
|
16
|
+
## When to Use
|
|
17
|
+
|
|
18
|
+
When the user asks to create, scaffold, or design a new skill for the agent.
|
|
19
|
+
|
|
20
|
+
## Skill Structure
|
|
21
|
+
|
|
22
|
+
A skill consists of two files in a directory under `~/.onecode/skills/<name>/`:
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
skill-name/
|
|
26
|
+
├── SKILL.md # Instructions with YAML frontmatter
|
|
27
|
+
└── skill.yaml # Metadata config
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Naming Rules
|
|
31
|
+
|
|
32
|
+
- Lowercase alphanumeric with single hyphens: `^[a-z0-9]+(-[a-z0-9]+)*$`
|
|
33
|
+
- 1-64 characters
|
|
34
|
+
- Good: `my-skill`, `code-review`, `deploy-aws`
|
|
35
|
+
- Bad: `MySkill`, `my--skill`, `-skill`
|
|
36
|
+
|
|
37
|
+
## SKILL.md Format
|
|
38
|
+
|
|
39
|
+
Start with YAML frontmatter (between `---` markers), then markdown body:
|
|
40
|
+
|
|
41
|
+
```markdown
|
|
42
|
+
---
|
|
43
|
+
name: my-skill
|
|
44
|
+
description: What this skill does
|
|
45
|
+
enabled: true
|
|
46
|
+
triggers:
|
|
47
|
+
- phrase that triggers
|
|
48
|
+
- another trigger
|
|
49
|
+
allowed_tools:
|
|
50
|
+
- Bash
|
|
51
|
+
- Read
|
|
52
|
+
phases:
|
|
53
|
+
- plan
|
|
54
|
+
- verify
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
# My Skill
|
|
58
|
+
|
|
59
|
+
## Instructions
|
|
60
|
+
...
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Frontmatter Fields
|
|
64
|
+
|
|
65
|
+
| Field | Required | Description |
|
|
66
|
+
|-------|----------|-------------|
|
|
67
|
+
| name | yes | Skill name (matches dir name) |
|
|
68
|
+
| description | yes | 1-1024 chars |
|
|
69
|
+
| enabled | no | true/false (default true) |
|
|
70
|
+
| triggers | no | Phrases that trigger this skill |
|
|
71
|
+
| allowed_tools | no | Restrict which tools available |
|
|
72
|
+
| arguments | no | Args accepted from user |
|
|
73
|
+
| phases | no | Lifecycle phases this applies to |
|
|
74
|
+
| license | no | License identifier |
|
|
75
|
+
| compatibility | no | Version/engine compatibility |
|
|
76
|
+
|
|
77
|
+
## Creating a Skill
|
|
78
|
+
|
|
79
|
+
### Via CLI
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
cdh skill create my-skill --description "Description here"
|
|
83
|
+
cdh skill create my-skill -d "Short description"
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Via API (Python)
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from onecode.skills import create_skill_scaffold
|
|
90
|
+
create_skill_scaffold(skills_dir, name="my-skill", description="...")
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Manual
|
|
94
|
+
|
|
95
|
+
1. Create `~/.onecode/skills/<name>/` directory
|
|
96
|
+
2. Write `SKILL.md` with frontmatter + instructions
|
|
97
|
+
3. Write `skill.yaml` with metadata
|
|
98
|
+
4. Run `cdh skill list` to verify it shows up
|
|
99
|
+
|
|
100
|
+
## Best Practices
|
|
101
|
+
|
|
102
|
+
- Keep SKILL.md focused and actionable
|
|
103
|
+
- Use clear headings and bullet lists
|
|
104
|
+
- Include concrete examples and code snippets
|
|
105
|
+
- Specify triggers so the agent knows when to activate
|
|
106
|
+
- Test with `cdh skill enable/disable` toggle
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
name: skill-creator
|
|
2
|
+
description: >-
|
|
3
|
+
Meta-skill for creating new agent skills. Teaches the agent how to design,
|
|
4
|
+
scaffold, and write effective SKILL.md files with proper frontmatter,
|
|
5
|
+
conventions, and tool integration.
|
|
6
|
+
version: 1.0.0
|
|
7
|
+
enabled: true
|
|
8
|
+
entry: SKILL.md
|
package/onecode/cli.py
CHANGED
|
@@ -2,12 +2,11 @@ import click
|
|
|
2
2
|
import logging
|
|
3
3
|
from logging.handlers import TimedRotatingFileHandler
|
|
4
4
|
from pathlib import Path
|
|
5
|
-
from typing import Optional
|
|
6
5
|
|
|
7
|
-
from onecode.config import
|
|
6
|
+
from onecode.config import load_config, save_config
|
|
8
7
|
|
|
9
|
-
LOG_DIR = Path.home() / ".
|
|
10
|
-
LOG_FILE = LOG_DIR / "
|
|
8
|
+
LOG_DIR = Path.home() / ".onecode" / "logs"
|
|
9
|
+
LOG_FILE = LOG_DIR / "onecode.log"
|
|
11
10
|
LOG_BACKUP_COUNT = 7 # keep 7 days of history
|
|
12
11
|
|
|
13
12
|
_VALID_LOG_LEVELS = {"DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"}
|
|
@@ -277,6 +276,73 @@ def skill_disable(name):
|
|
|
277
276
|
_toggle_skill(name, enabled=False)
|
|
278
277
|
|
|
279
278
|
|
|
279
|
+
@skill.command("create")
|
|
280
|
+
@click.argument("name")
|
|
281
|
+
@click.option("--description", "-d", default="", help="Skill description")
|
|
282
|
+
def skill_create(name, description):
|
|
283
|
+
"""Create a new skill scaffold.
|
|
284
|
+
|
|
285
|
+
\b
|
|
286
|
+
Creates SKILL.md and skill.yaml in ~/.onecode/skills/<name>/.
|
|
287
|
+
Edit the generated SKILL.md to add your instructions.
|
|
288
|
+
|
|
289
|
+
\b
|
|
290
|
+
Example:
|
|
291
|
+
cdh skill create my-skill -d "My custom skill"
|
|
292
|
+
"""
|
|
293
|
+
from onecode.skills.create import create_skill_scaffold
|
|
294
|
+
from onecode.skills.manager import SkillManager
|
|
295
|
+
from onecode.skills.model import Skill as SkillModel
|
|
296
|
+
|
|
297
|
+
valid, err = SkillModel.validate_name(name)
|
|
298
|
+
if not valid:
|
|
299
|
+
click.echo(f"Error: Invalid skill name: {err}")
|
|
300
|
+
return
|
|
301
|
+
if description:
|
|
302
|
+
valid, err = SkillModel.validate_description(description)
|
|
303
|
+
if not valid:
|
|
304
|
+
click.echo(f"Error: Invalid description: {err}")
|
|
305
|
+
return
|
|
306
|
+
|
|
307
|
+
mgr = SkillManager()
|
|
308
|
+
err = create_skill_scaffold(mgr.skills_dir, name, description or f"A skill for {name}")
|
|
309
|
+
if err:
|
|
310
|
+
click.echo(f"Error: {err}")
|
|
311
|
+
else:
|
|
312
|
+
click.echo(f"Skill '{name}' created at {mgr.skills_dir / name}")
|
|
313
|
+
click.echo(f" Edit {mgr.skills_dir / name / 'SKILL.md'} to add instructions.")
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
@skill.command("search")
|
|
317
|
+
@click.argument("keyword")
|
|
318
|
+
def skill_search(keyword):
|
|
319
|
+
"""Search installed skills by keyword.
|
|
320
|
+
|
|
321
|
+
Matches against name, description, triggers, and phases.
|
|
322
|
+
Case-insensitive.
|
|
323
|
+
|
|
324
|
+
\b
|
|
325
|
+
Example:
|
|
326
|
+
cdh skill search browser
|
|
327
|
+
"""
|
|
328
|
+
from onecode.skills.loader import SkillLoader
|
|
329
|
+
|
|
330
|
+
loader = SkillLoader()
|
|
331
|
+
results = loader.search(keyword)
|
|
332
|
+
|
|
333
|
+
if not results:
|
|
334
|
+
click.echo(f"No skills found matching '{keyword}'.")
|
|
335
|
+
return
|
|
336
|
+
|
|
337
|
+
click.echo(f"Skills matching '{keyword}':")
|
|
338
|
+
for s in results:
|
|
339
|
+
status = "[enabled]" if s.enabled else "[disabled]"
|
|
340
|
+
click.echo(f" {status} {s.name}")
|
|
341
|
+
if s.description:
|
|
342
|
+
click.echo(f" {s.description}")
|
|
343
|
+
click.echo(f"\nTotal: {len(results)} match(es)")
|
|
344
|
+
|
|
345
|
+
|
|
280
346
|
def _toggle_skill(name: str, enabled: bool):
|
|
281
347
|
import yaml
|
|
282
348
|
from onecode.skills.loader import SkillLoader
|
|
@@ -373,6 +439,56 @@ def config_skill_disable(name):
|
|
|
373
439
|
_toggle_skill(name, enabled=False)
|
|
374
440
|
|
|
375
441
|
|
|
442
|
+
@config_skill.command("create")
|
|
443
|
+
@click.argument("name")
|
|
444
|
+
@click.option("--description", "-d", default="", help="Skill description")
|
|
445
|
+
def config_skill_create(name, description):
|
|
446
|
+
"""Create a new skill scaffold (alias for cdh skill create)."""
|
|
447
|
+
from onecode.skills.create import create_skill_scaffold
|
|
448
|
+
from onecode.skills.manager import SkillManager
|
|
449
|
+
from onecode.skills.model import Skill as SkillModel
|
|
450
|
+
|
|
451
|
+
valid, err = SkillModel.validate_name(name)
|
|
452
|
+
if not valid:
|
|
453
|
+
click.echo(f"Error: Invalid skill name: {err}")
|
|
454
|
+
return
|
|
455
|
+
if description:
|
|
456
|
+
valid, err = SkillModel.validate_description(description)
|
|
457
|
+
if not valid:
|
|
458
|
+
click.echo(f"Error: Invalid description: {err}")
|
|
459
|
+
return
|
|
460
|
+
|
|
461
|
+
mgr = SkillManager()
|
|
462
|
+
err = create_skill_scaffold(mgr.skills_dir, name, description or f"A skill for {name}")
|
|
463
|
+
if err:
|
|
464
|
+
click.echo(f"Error: {err}")
|
|
465
|
+
else:
|
|
466
|
+
click.echo(f"Skill '{name}' created at {mgr.skills_dir / name}")
|
|
467
|
+
click.echo(f" Edit {mgr.skills_dir / name / 'SKILL.md'} to add instructions.")
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
@config_skill.command("search")
|
|
471
|
+
@click.argument("keyword")
|
|
472
|
+
def config_skill_search(keyword):
|
|
473
|
+
"""Search installed skills by keyword (alias for cdh skill search)."""
|
|
474
|
+
from onecode.skills.loader import SkillLoader
|
|
475
|
+
|
|
476
|
+
loader = SkillLoader()
|
|
477
|
+
results = loader.search(keyword)
|
|
478
|
+
|
|
479
|
+
if not results:
|
|
480
|
+
click.echo(f"No skills found matching '{keyword}'.")
|
|
481
|
+
return
|
|
482
|
+
|
|
483
|
+
click.echo(f"Skills matching '{keyword}':")
|
|
484
|
+
for s in results:
|
|
485
|
+
status = "[enabled]" if s.enabled else "[disabled]"
|
|
486
|
+
click.echo(f" {status} {s.name}")
|
|
487
|
+
if s.description:
|
|
488
|
+
click.echo(f" {s.description}")
|
|
489
|
+
click.echo(f"\nTotal: {len(results)} match(es)")
|
|
490
|
+
|
|
491
|
+
|
|
376
492
|
@cli.group(invoke_without_command=True)
|
|
377
493
|
def mcp():
|
|
378
494
|
"""Manage MCP (Model Context Protocol) servers.
|
|
@@ -619,7 +735,7 @@ def codebase():
|
|
|
619
735
|
def codebase_index(force: bool, path: str):
|
|
620
736
|
"""Index project files for codebase search."""
|
|
621
737
|
import asyncio
|
|
622
|
-
from onecode.codebase import CodebaseEngine
|
|
738
|
+
from onecode.codebase import CodebaseEngine
|
|
623
739
|
|
|
624
740
|
project_dir = Path(path).resolve()
|
|
625
741
|
if not project_dir.is_dir():
|
|
@@ -630,7 +746,6 @@ def codebase_index(force: bool, path: str):
|
|
|
630
746
|
engine = CodebaseEngine(project_dir, cfg.codebase)
|
|
631
747
|
result = asyncio.run(engine.ensure_indexed(force=force))
|
|
632
748
|
|
|
633
|
-
total = result.total_files if hasattr(result, 'total_files') else 0
|
|
634
749
|
click.echo(
|
|
635
750
|
f"Indexed {project_dir.name}: "
|
|
636
751
|
f"{result.indexed_files} files, "
|
|
@@ -721,6 +836,71 @@ def codebase_reindex(path: str):
|
|
|
721
836
|
)
|
|
722
837
|
|
|
723
838
|
|
|
839
|
+
@cli.group()
|
|
840
|
+
def memory():
|
|
841
|
+
"""Manage long-term memory.
|
|
842
|
+
|
|
843
|
+
\b
|
|
844
|
+
Memory stores conversation history with BM25 keyword recall.
|
|
845
|
+
Use `cdh memory status` to view memory usage and `cdh memory clear` to reset.
|
|
846
|
+
"""
|
|
847
|
+
pass
|
|
848
|
+
|
|
849
|
+
|
|
850
|
+
@memory.command("status")
|
|
851
|
+
def memory_status():
|
|
852
|
+
"""Show memory usage statistics."""
|
|
853
|
+
from onecode.memory.backend import MemoryBackend
|
|
854
|
+
|
|
855
|
+
backend = MemoryBackend()
|
|
856
|
+
counts = backend.count_by_layer()
|
|
857
|
+
total = sum(counts.values())
|
|
858
|
+
click.echo(f"Total entries: {total}")
|
|
859
|
+
for layer, count in counts.items():
|
|
860
|
+
click.echo(f" {layer}: {count}")
|
|
861
|
+
if total == 0:
|
|
862
|
+
click.echo(" (no memories stored yet)")
|
|
863
|
+
|
|
864
|
+
|
|
865
|
+
@memory.command("clear")
|
|
866
|
+
@click.option("--layer", default=None, help="Layer to clear (default: all layers)")
|
|
867
|
+
def memory_clear(layer: str):
|
|
868
|
+
"""Clear memory entries."""
|
|
869
|
+
from onecode.memory import AgentMemory
|
|
870
|
+
from onecode.memory.pyramid import MemoryLayer
|
|
871
|
+
|
|
872
|
+
am = AgentMemory()
|
|
873
|
+
if layer:
|
|
874
|
+
layers_to_clear = [l for l in MemoryLayer if l.value == layer]
|
|
875
|
+
else:
|
|
876
|
+
layers_to_clear = list(MemoryLayer)
|
|
877
|
+
removed = 0
|
|
878
|
+
for l in layers_to_clear:
|
|
879
|
+
entries = am.pyramid.list_by_layer(l)
|
|
880
|
+
for e in entries:
|
|
881
|
+
am.pyramid._layers[l].remove(e)
|
|
882
|
+
am.backend.delete_entry(e.id)
|
|
883
|
+
removed += 1
|
|
884
|
+
click.echo(f"Cleared {removed} memory entries.")
|
|
885
|
+
|
|
886
|
+
|
|
887
|
+
@memory.command("count")
|
|
888
|
+
@click.option("--layer", default=None, help="Layer to count (default: all layers)")
|
|
889
|
+
def memory_count(layer: str):
|
|
890
|
+
"""Count memory entries."""
|
|
891
|
+
from onecode.memory.backend import MemoryBackend
|
|
892
|
+
|
|
893
|
+
backend = MemoryBackend()
|
|
894
|
+
counts = backend.count_by_layer()
|
|
895
|
+
if layer:
|
|
896
|
+
click.echo(f"Entries in {layer}: {counts.get(layer, 0)}")
|
|
897
|
+
else:
|
|
898
|
+
total = sum(counts.values())
|
|
899
|
+
click.echo(f"Total entries: {total}")
|
|
900
|
+
for ly, count in sorted(counts.items()):
|
|
901
|
+
click.echo(f" {ly}: {count}")
|
|
902
|
+
|
|
903
|
+
|
|
724
904
|
@cli.command()
|
|
725
905
|
@click.argument("command", required=False)
|
|
726
906
|
@click.option("--list", "list_commands", is_flag=True, help="List all available commands")
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -3,7 +3,6 @@ from __future__ import annotations
|
|
|
3
3
|
import os
|
|
4
4
|
from dataclasses import dataclass
|
|
5
5
|
from pathlib import Path
|
|
6
|
-
from typing import Optional
|
|
7
6
|
|
|
8
7
|
|
|
9
8
|
_LANG_MAP: dict[str, str] = {
|
|
@@ -64,10 +63,6 @@ def detect_language(file_path: str) -> str:
|
|
|
64
63
|
|
|
65
64
|
def chunk_file(file_path: Path, strategy: str = "line",
|
|
66
65
|
chunk_lines: int = 50, overlap: int = 10) -> list[CodeChunk]:
|
|
67
|
-
if strategy == "line":
|
|
68
|
-
return _chunk_by_lines(file_path, chunk_lines, overlap)
|
|
69
|
-
if strategy == "ast":
|
|
70
|
-
return _chunk_by_lines(file_path, chunk_lines, overlap)
|
|
71
66
|
return _chunk_by_lines(file_path, chunk_lines, overlap)
|
|
72
67
|
|
|
73
68
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
import asyncio
|
|
3
4
|
import logging
|
|
4
5
|
import os
|
|
5
6
|
import time
|
|
@@ -82,7 +83,19 @@ class CodebaseIndexer:
|
|
|
82
83
|
files = self.walk_files()
|
|
83
84
|
result.total_files = len(files)
|
|
84
85
|
|
|
85
|
-
|
|
86
|
+
# Yield control to the event loop periodically so:
|
|
87
|
+
# - CancelledError injected by ``prompt_task.cancel()`` during a
|
|
88
|
+
# subagent chat_stream can actually propagate (without this
|
|
89
|
+
# the synchronous SQLite/chunker loop below would monopolise
|
|
90
|
+
# the event loop and a stuck subagent could never be stopped).
|
|
91
|
+
# - other coroutines (e.g. the ACP stdin loop, TUI refresh) keep
|
|
92
|
+
# getting scheduled while a long indexing pass runs.
|
|
93
|
+
_YIELD_EVERY = 16
|
|
94
|
+
|
|
95
|
+
for i, fpath in enumerate(files):
|
|
96
|
+
if i and (i % _YIELD_EVERY) == 0:
|
|
97
|
+
await asyncio.sleep(0)
|
|
98
|
+
|
|
86
99
|
if not force and not self.needs_reindex(fpath):
|
|
87
100
|
result.skipped_files += 1
|
|
88
101
|
continue
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import json
|
|
4
3
|
import logging
|
|
5
4
|
import math
|
|
6
5
|
from typing import Optional
|
|
@@ -147,11 +146,23 @@ async def _get_batch_embeddings(texts: list[str], config: CodebaseConfig) -> lis
|
|
|
147
146
|
provider_name = config.embedding_provider or cfg.default_provider
|
|
148
147
|
pcfg = cfg.providers.get(provider_name)
|
|
149
148
|
|
|
149
|
+
MAX_EMBED_CHUNKS = 500
|
|
150
|
+
if len(texts) > MAX_EMBED_CHUNKS:
|
|
151
|
+
import logging
|
|
152
|
+
logging.getLogger(__name__).warning(
|
|
153
|
+
"Embedding requested on %d chunks (max=%d); truncating to avoid timeout",
|
|
154
|
+
len(texts), MAX_EMBED_CHUNKS,
|
|
155
|
+
)
|
|
156
|
+
texts = texts[:MAX_EMBED_CHUNKS]
|
|
157
|
+
|
|
150
158
|
if provider_name == "ollama" and pcfg:
|
|
151
159
|
embs = await _ollama_batch_embed(texts, pcfg.endpoint or "http://localhost:11434")
|
|
152
160
|
else:
|
|
153
161
|
embs = []
|
|
154
|
-
for t in texts:
|
|
162
|
+
for i, t in enumerate(texts):
|
|
163
|
+
if i > 0 and i % 16 == 0:
|
|
164
|
+
import asyncio
|
|
165
|
+
await asyncio.sleep(0)
|
|
155
166
|
emb = await _get_embedding(t, config)
|
|
156
167
|
embs.append(emb)
|
|
157
168
|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import hashlib
|
|
4
4
|
from pathlib import Path
|
|
5
|
-
from typing import Optional
|
|
6
5
|
|
|
7
6
|
from sqlalchemy import Column, String, Text, Integer, Float, create_engine, Index
|
|
8
|
-
from sqlalchemy.orm import declarative_base, sessionmaker
|
|
7
|
+
from sqlalchemy.orm import declarative_base, sessionmaker
|
|
9
8
|
|
|
10
9
|
from onecode.codebase.chunker import CodeChunk
|
|
10
|
+
from onecode.config import ONECODE_DIR
|
|
11
11
|
|
|
12
12
|
Base = declarative_base()
|
|
13
13
|
|
|
@@ -31,7 +31,8 @@ class ChunkRecord(Base):
|
|
|
31
31
|
|
|
32
32
|
class CodebaseStorage:
|
|
33
33
|
def __init__(self, project_dir: Path):
|
|
34
|
-
|
|
34
|
+
project_key = hashlib.sha256(str(project_dir.resolve()).encode()).hexdigest()[:16]
|
|
35
|
+
db_dir = ONECODE_DIR / "codebase" / "indexes" / project_key
|
|
35
36
|
db_dir.mkdir(parents=True, exist_ok=True)
|
|
36
37
|
self.db_path = db_dir / "index.db"
|
|
37
38
|
self.engine = create_engine(f"sqlite:///{self.db_path}", echo=False)
|
package/onecode/commands.py
CHANGED
|
@@ -310,6 +310,51 @@ async def _skill(conversation: "Conversation", parameters: str) -> None:
|
|
|
310
310
|
await _skill(conversation, "list")
|
|
311
311
|
return
|
|
312
312
|
|
|
313
|
+
if sub == "create":
|
|
314
|
+
name = rest.strip()
|
|
315
|
+
if not name:
|
|
316
|
+
conversation.notify("Usage: /onecode:skill create <name>", title="/onecode:skill create", severity="error")
|
|
317
|
+
return
|
|
318
|
+
from onecode.skills.model import Skill as SkillModel
|
|
319
|
+
valid, err_msg = SkillModel.validate_name(name)
|
|
320
|
+
if not valid:
|
|
321
|
+
conversation.notify(f"Invalid name: {err_msg}", title="/onecode:skill create", severity="error")
|
|
322
|
+
return
|
|
323
|
+
mgr = SkillManager()
|
|
324
|
+
if mgr.get(name):
|
|
325
|
+
conversation.notify(f"Skill '{name}' already exists", title="/onecode:skill create", severity="error")
|
|
326
|
+
return
|
|
327
|
+
err = create_skill_scaffold(mgr.skills_dir, name, f"A skill for {name}")
|
|
328
|
+
if err:
|
|
329
|
+
conversation.notify(f"Error: {err}", title="/onecode:skill create", severity="error")
|
|
330
|
+
return
|
|
331
|
+
await _post(
|
|
332
|
+
conversation,
|
|
333
|
+
f"**Skill '{name}' created**\n\n"
|
|
334
|
+
f"- location: `{mgr.skills_dir / name}`\n"
|
|
335
|
+
f"- edit `SKILL.md` to add instructions\n"
|
|
336
|
+
f"- then `/onecode:skill list` to confirm",
|
|
337
|
+
)
|
|
338
|
+
return
|
|
339
|
+
|
|
340
|
+
if sub in ("search", "find"):
|
|
341
|
+
keyword = rest.strip()
|
|
342
|
+
if not keyword:
|
|
343
|
+
conversation.notify("Usage: /onecode:skill search <keyword>", title="/onecode:skill search", severity="error")
|
|
344
|
+
return
|
|
345
|
+
results = SkillLoader().search(keyword)
|
|
346
|
+
if not results:
|
|
347
|
+
await _post(conversation, f"**Skill Search: `{keyword}`**\n\n_No matches found._")
|
|
348
|
+
return
|
|
349
|
+
lines = [f"**Skill Search: `{keyword}`**\n"]
|
|
350
|
+
for i, s in enumerate(results, 1):
|
|
351
|
+
marker = "✓" if s.enabled else "✗"
|
|
352
|
+
desc = s.description or "(no description)"
|
|
353
|
+
lines.append(f"- `{i}) {marker}` **{s.name}** — {desc}")
|
|
354
|
+
lines.append(f"\n{len(results)} match(es)")
|
|
355
|
+
await _post(conversation, "\n".join(lines))
|
|
356
|
+
return
|
|
357
|
+
|
|
313
358
|
await _post(conversation, _HELP_SKILL)
|
|
314
359
|
|
|
315
360
|
|
|
@@ -317,14 +362,17 @@ _HELP_SKILL = (
|
|
|
317
362
|
"**/onecode:skill** — manage installed skills\n\n"
|
|
318
363
|
"**Sub-commands**\n"
|
|
319
364
|
"- `(none)` or `list` — show all skills with status\n"
|
|
365
|
+
"- `create <name>` — scaffold a new skill\n"
|
|
366
|
+
"- `search <keyword>` — search skills by keyword\n"
|
|
320
367
|
"- `enable <name|n>` — turn a skill on\n"
|
|
321
368
|
"- `disable <name|n>` — turn a skill off\n"
|
|
322
|
-
"- `add <name>` — scaffold a new skill\n"
|
|
369
|
+
"- `add <name>` — scaffold a new skill (alias for create)\n"
|
|
323
370
|
"- `remove <name|n>` — delete a skill\n\n"
|
|
324
371
|
"**Examples**\n"
|
|
325
372
|
"- `/onecode:skill` — list\n"
|
|
326
|
-
"- `/onecode:skill
|
|
327
|
-
"- `/onecode:skill
|
|
373
|
+
"- `/onecode:skill create my-skill` — scaffold a new skill\n"
|
|
374
|
+
"- `/onecode:skill search browser` — find browser-related skills\n"
|
|
375
|
+
"- `/onecode:skill enable 2` — enable the skill at index 2"
|
|
328
376
|
)
|
|
329
377
|
|
|
330
378
|
|
|
@@ -349,7 +397,6 @@ async def _mcp(conversation: "Conversation", parameters: str) -> None:
|
|
|
349
397
|
)
|
|
350
398
|
return
|
|
351
399
|
lines = ["**MCP Servers**\n"]
|
|
352
|
-
names = [s.get("name", "?") for s in servers]
|
|
353
400
|
for i, s in enumerate(servers, 1):
|
|
354
401
|
name = s.get("name", "?")
|
|
355
402
|
transport = s.get("transport", "sse")
|
|
@@ -473,6 +520,28 @@ def _resolve_indexed_name(conversation, raw, items, sub_label):
|
|
|
473
520
|
return None
|
|
474
521
|
|
|
475
522
|
|
|
523
|
+
# ── clear-todos ──────────────────────────────────────────────────────────
|
|
524
|
+
|
|
525
|
+
|
|
526
|
+
async def _clear_todos(conversation: "Conversation", parameters: str) -> None:
|
|
527
|
+
"""Clear all todos via the agent's session/clear_todos RPC."""
|
|
528
|
+
agent = conversation.agent
|
|
529
|
+
if agent is None:
|
|
530
|
+
conversation.notify("No active agent session", title="/clear-todos", severity="error")
|
|
531
|
+
return
|
|
532
|
+
if not hasattr(agent, "acp_session_clear_todos"):
|
|
533
|
+
conversation.notify("Agent does not support clear-todos", title="/clear-todos", severity="error")
|
|
534
|
+
return
|
|
535
|
+
try:
|
|
536
|
+
result = await agent.acp_session_clear_todos()
|
|
537
|
+
if result and result.get("cleared"):
|
|
538
|
+
conversation.notify("All todos cleared", title="/clear-todos")
|
|
539
|
+
else:
|
|
540
|
+
conversation.notify("Failed to clear todos", title="/clear-todos", severity="error")
|
|
541
|
+
except Exception as e:
|
|
542
|
+
conversation.notify(f"Failed to clear todos: {e}", title="/clear-todos", severity="error")
|
|
543
|
+
|
|
544
|
+
|
|
476
545
|
# ── registration ──────────────────────────────────────────────────────
|
|
477
546
|
|
|
478
547
|
|
|
@@ -509,13 +578,19 @@ def register_commands() -> None:
|
|
|
509
578
|
)
|
|
510
579
|
platform_commands.register(
|
|
511
580
|
"skill",
|
|
512
|
-
"Manage skills: list, enable, disable, add, remove (accepts name or list number)",
|
|
581
|
+
"Manage skills: list, create, search, enable, disable, add, remove (accepts name or list number)",
|
|
513
582
|
_skill,
|
|
514
|
-
"list|enable|disable|add|remove [name|n]",
|
|
583
|
+
"list|create|search|enable|disable|add|remove [name|n]",
|
|
515
584
|
)
|
|
516
585
|
platform_commands.register(
|
|
517
586
|
"mcp",
|
|
518
587
|
"Manage MCP servers: list, add, enable, disable, remove (accepts name or list number)",
|
|
519
588
|
_mcp,
|
|
520
589
|
"list|add|enable|disable|remove [name|n]",
|
|
590
|
+
)
|
|
591
|
+
platform_commands.register(
|
|
592
|
+
"clear-todos",
|
|
593
|
+
"Clear all plan todos — starts a fresh blank plan",
|
|
594
|
+
_clear_todos,
|
|
595
|
+
"(no args)",
|
|
521
596
|
)
|