@scemoon/cdh 1.0.3 → 1.0.5

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 (294) hide show
  1. package/ai-dlc-skill/SKILL.md +4 -2
  2. package/ai-dlc-skill/agents/master.md +6 -0
  3. package/ai-dlc-skill/agents/plan-agent.md +2 -2
  4. package/ai-dlc-skill/agents/understand-agent.md +4 -4
  5. package/ai-dlc-skill/agents/verify-agent.md +1 -1
  6. package/ai-dlc-skill/architecture/project-structure.md +10 -10
  7. package/ai-dlc-skill/brownfield/README.md +2 -2
  8. package/ai-dlc-skill/brownfield/generate-context.sh +3 -3
  9. package/ai-dlc-skill/brownfield/scripts/extract-api.sh +5 -5
  10. package/ai-dlc-skill/components/backend.md +1 -1
  11. package/ai-dlc-skill/components/web.md +2 -2
  12. package/ai-dlc-skill/contracts/README.md +3 -3
  13. package/ai-dlc-skill/cross-tool/cline/export.sh +1 -1
  14. package/ai-dlc-skill/cross-tool/copilot/export.sh +1 -1
  15. package/ai-dlc-skill/cross-tool/onecode/export-skills.sh +7 -3
  16. package/ai-dlc-skill/cross-tool/onecode/export.sh +14 -8
  17. package/ai-dlc-skill/phases/deliver/lifecycle.md +6 -6
  18. package/ai-dlc-skill/phases/deliver/prompt.md +2 -2
  19. package/ai-dlc-skill/phases/deliver/rules.md +1 -1
  20. package/ai-dlc-skill/phases/plan/lifecycle.md +11 -11
  21. package/ai-dlc-skill/phases/plan/prompt.md +6 -6
  22. package/ai-dlc-skill/phases/plan/rules.md +1 -1
  23. package/ai-dlc-skill/phases/understand/entry.md +1 -1
  24. package/ai-dlc-skill/phases/understand/lifecycle.md +7 -7
  25. package/ai-dlc-skill/phases/understand/prompt.md +8 -8
  26. package/ai-dlc-skill/phases/understand/rules.md +5 -5
  27. package/ai-dlc-skill/phases/verify/lifecycle.md +24 -24
  28. package/ai-dlc-skill/phases/verify/prompt.md +8 -8
  29. package/ai-dlc-skill/phases/verify/rules.md +9 -9
  30. package/ai-dlc-skill/providers/README.md +2 -2
  31. package/ai-dlc-skill/providers/aliyun/preview.yaml +2 -2
  32. package/ai-dlc-skill/providers/tcb/preview.yaml +2 -2
  33. package/ai-dlc-skill/requirements.md +7 -7
  34. package/ai-dlc-skill/skill.yaml +4 -4
  35. package/ai-dlc-skill/templates/integration/CHANGELOG.md +2 -2
  36. package/ai-dlc-skill/templates/integration/contract-diff.md +7 -7
  37. package/ai-dlc-skill/templates/integration/contract-spec.md +7 -7
  38. package/ai-dlc-skill/templates/integration/runtime-contract.yaml +1 -1
  39. package/ai-dlc-skill/templates/project/README.md +18 -19
  40. package/ai-dlc-skill/templates/project/template.md +21 -21
  41. package/ai-dlc-skill/walkthrough/collect.sh +1 -1
  42. package/ai-dlc-skill/walkthrough/template.md +2 -2
  43. package/ai-dlc-skill/workflows/ai-dlc.yaml +12 -12
  44. package/ai-dlc-skill/workflows/deployment.yaml +4 -4
  45. package/cdh/__pycache__/cdh_mcp_injector.cpython-314.pyc +0 -0
  46. package/cdh/__pycache__/cdh_mcp_loader.cpython-314.pyc +0 -0
  47. package/cdh/__pycache__/cdh_mcp_manager.cpython-314.pyc +0 -0
  48. package/cdh/__pycache__/cdh_session_aggregator.cpython-314.pyc +0 -0
  49. package/cdh/__pycache__/cdh_skill_loader.cpython-314.pyc +0 -0
  50. package/cdh/__pycache__/cdh_skill_manager.cpython-314.pyc +0 -0
  51. package/cdh/__pycache__/cli.cpython-313.pyc +0 -0
  52. package/cdh/__pycache__/cli.cpython-314.pyc +0 -0
  53. package/cdh/__pycache__/scaffold.cpython-314.pyc +0 -0
  54. package/cdh/cdh_mcp_injector.py +115 -0
  55. package/cdh/cdh_mcp_loader.py +67 -0
  56. package/cdh/cdh_mcp_manager.py +73 -0
  57. package/cdh/cdh_session_aggregator.py +258 -0
  58. package/cdh/cdh_skill_manager.py +105 -0
  59. package/cdh/cli.py +14 -3
  60. package/cdh/scaffold.py +192 -41
  61. package/onecode/__init__.py +1 -1
  62. package/onecode/__pycache__/cli.cpython-314.pyc +0 -0
  63. package/onecode/__pycache__/commands.cpython-314.pyc +0 -0
  64. package/onecode/__pycache__/config.cpython-314.pyc +0 -0
  65. package/onecode/__pycache__/config_screen.cpython-314.pyc +0 -0
  66. package/onecode/__pycache__/migrate.cpython-314.pyc +0 -0
  67. package/onecode/agent/__pycache__/cdh_loader.cpython-314.pyc +0 -0
  68. package/onecode/agent/__pycache__/context.cpython-314.pyc +0 -0
  69. package/onecode/agent/__pycache__/engine.cpython-314.pyc +0 -0
  70. package/onecode/agent/__pycache__/hooks.cpython-314.pyc +0 -0
  71. package/onecode/agent/__pycache__/onecode_agent_acp.cpython-314.pyc +0 -0
  72. package/onecode/agent/__pycache__/permissions.cpython-314.pyc +0 -0
  73. package/onecode/agent/__pycache__/project_doc.cpython-314.pyc +0 -0
  74. package/onecode/agent/__pycache__/session.cpython-314.pyc +0 -0
  75. package/onecode/agent/agents/__pycache__/types.cpython-314.pyc +0 -0
  76. package/onecode/agent/agents/types.py +47 -164
  77. package/onecode/agent/attachments.py +0 -1
  78. package/onecode/agent/cdh_loader.py +17 -25
  79. package/onecode/agent/context.py +8 -3
  80. package/onecode/agent/engine.py +835 -220
  81. package/onecode/agent/hooks.py +1 -1
  82. package/onecode/agent/onecode_agent_acp.py +462 -49
  83. package/onecode/agent/onecode_agent_acp.py.bak +2447 -0
  84. package/onecode/agent/permissions.py +0 -1
  85. package/onecode/agent/project_doc.py +19 -0
  86. package/onecode/agent/session.py +17 -3
  87. package/onecode/agent/snapshot.py +3 -4
  88. package/onecode/agent/tools/__pycache__/agent_tools.cpython-314.pyc +0 -0
  89. package/onecode/agent/tools/__pycache__/apply_patch_tool.cpython-314.pyc +0 -0
  90. package/onecode/agent/tools/__pycache__/bash_tool.cpython-314.pyc +0 -0
  91. package/onecode/agent/tools/__pycache__/communication_tools.cpython-314.pyc +0 -0
  92. package/onecode/agent/tools/__pycache__/config_tool.cpython-314.pyc +0 -0
  93. package/onecode/agent/tools/__pycache__/cron_tools.cpython-314.pyc +0 -0
  94. package/onecode/agent/tools/__pycache__/file_ops.cpython-314.pyc +0 -0
  95. package/onecode/agent/tools/__pycache__/file_tools.cpython-314.pyc +0 -0
  96. package/onecode/agent/tools/__pycache__/git_tools.cpython-314.pyc +0 -0
  97. package/onecode/agent/tools/__pycache__/lsp_tools.cpython-314.pyc +0 -0
  98. package/onecode/agent/tools/__pycache__/mcp_tools.cpython-314.pyc +0 -0
  99. package/onecode/agent/tools/__pycache__/permission_handler.cpython-314.pyc +0 -0
  100. package/onecode/agent/tools/__pycache__/protocol.cpython-314.pyc +0 -0
  101. package/onecode/agent/tools/__pycache__/registry.cpython-314.pyc +0 -0
  102. package/onecode/agent/tools/__pycache__/sandbox.cpython-314.pyc +0 -0
  103. package/onecode/agent/tools/__pycache__/skill_tools.cpython-314.pyc +0 -0
  104. package/onecode/agent/tools/__pycache__/todo_tools.cpython-314.pyc +0 -0
  105. package/onecode/agent/tools/__pycache__/web_tools.cpython-314.pyc +0 -0
  106. package/onecode/agent/tools/agent_tools.py +4 -6
  107. package/onecode/agent/tools/apply_patch_tool.py +2 -8
  108. package/onecode/agent/tools/bash_tool.py +32 -12
  109. package/onecode/agent/tools/communication_tools.py +4 -5
  110. package/onecode/agent/tools/config_tool.py +3 -3
  111. package/onecode/agent/tools/cron_tools.py +4 -5
  112. package/onecode/agent/tools/file_ops.py +37 -3
  113. package/onecode/agent/tools/file_tools.py +10 -11
  114. package/onecode/agent/tools/git_tools.py +2 -2
  115. package/onecode/agent/tools/lsp_tools.py +2 -2
  116. package/onecode/agent/tools/mcp_tools.py +3 -5
  117. package/onecode/agent/tools/permission_handler.py +1 -1
  118. package/onecode/agent/tools/protocol.py +1 -1
  119. package/onecode/agent/tools/registry.py +69 -2
  120. package/onecode/agent/tools/sandbox.py +110 -16
  121. package/onecode/agent/tools/skill_tools.py +2 -2
  122. package/onecode/agent/tools/todo_tools.py +38 -19
  123. package/onecode/agent/tools/web_tools.py +6 -7
  124. package/onecode/builtin_skills/agent-browser/SKILL.md +212 -0
  125. package/onecode/builtin_skills/agent-browser/skill.yaml +8 -0
  126. package/onecode/builtin_skills/skill-creator/SKILL.md +106 -0
  127. package/onecode/builtin_skills/skill-creator/skill.yaml +8 -0
  128. package/onecode/cli.py +186 -6
  129. package/onecode/codebase/__pycache__/chunker.cpython-314.pyc +0 -0
  130. package/onecode/codebase/__pycache__/indexer.cpython-314.pyc +0 -0
  131. package/onecode/codebase/__pycache__/retriever.cpython-314.pyc +0 -0
  132. package/onecode/codebase/__pycache__/storage.cpython-314.pyc +0 -0
  133. package/onecode/codebase/chunker.py +0 -5
  134. package/onecode/codebase/indexer.py +14 -1
  135. package/onecode/codebase/retriever.py +13 -2
  136. package/onecode/codebase/storage.py +5 -4
  137. package/onecode/commands.py +81 -6
  138. package/onecode/config.py +41 -12
  139. package/onecode/config_screen.py +7 -3
  140. package/onecode/mcp/__pycache__/manager.cpython-314.pyc +0 -0
  141. package/onecode/mcp/manager.py +2 -3
  142. package/onecode/memory/__init__.py +7 -53
  143. package/onecode/memory/__pycache__/__init__.cpython-314.pyc +0 -0
  144. package/onecode/memory/__pycache__/backend.cpython-314.pyc +0 -0
  145. package/onecode/memory/__pycache__/offload.cpython-314.pyc +0 -0
  146. package/onecode/memory/__pycache__/pyramid.cpython-314.pyc +0 -0
  147. package/onecode/memory/__pycache__/recall.cpython-314.pyc +0 -0
  148. package/onecode/memory/backend.py +13 -39
  149. package/onecode/memory/pyramid.py +2 -71
  150. package/onecode/memory/recall.py +38 -3
  151. package/onecode/migrate.py +122 -0
  152. package/onecode/models/__pycache__/messages.cpython-314.pyc +0 -0
  153. package/onecode/models/__pycache__/provider.cpython-314.pyc +0 -0
  154. package/onecode/models/messages.py +58 -0
  155. package/onecode/models/provider.py +20 -2
  156. package/onecode/models/providers/__pycache__/anthropic_provider.cpython-314.pyc +0 -0
  157. package/onecode/models/providers/__pycache__/glm_provider.cpython-314.pyc +0 -0
  158. package/onecode/models/providers/__pycache__/minimax_provider.cpython-314.pyc +0 -0
  159. package/onecode/models/providers/__pycache__/minimaxi_provider.cpython-314.pyc +0 -0
  160. package/onecode/models/providers/__pycache__/ollama_provider.cpython-314.pyc +0 -0
  161. package/onecode/models/providers/anthropic_provider.py +59 -12
  162. package/onecode/models/providers/glm_provider.py +40 -0
  163. package/onecode/models/providers/minimax_provider.py +3 -0
  164. package/onecode/models/providers/minimaxi_provider.py +3 -0
  165. package/onecode/models/providers/ollama_provider.py +3 -0
  166. package/onecode/server/app.py +1 -1
  167. package/onecode/skills/__pycache__/argument_substitution.cpython-314.pyc +0 -0
  168. package/onecode/skills/__pycache__/bootstrap.cpython-314.pyc +0 -0
  169. package/onecode/skills/__pycache__/loader.cpython-314.pyc +0 -0
  170. package/onecode/skills/__pycache__/manager.cpython-314.pyc +0 -0
  171. package/onecode/skills/argument_substitution.py +0 -1
  172. package/onecode/skills/bootstrap.py +124 -0
  173. package/onecode/skills/loader.py +35 -53
  174. package/onecode/skills/manager.py +2 -2
  175. package/onecode/storage/activity.py +3 -4
  176. package/onecode/storage/session.py +3 -4
  177. package/onecode/tasks/manager.py +23 -10
  178. package/onecode/trace/tracer.py +2 -3
  179. package/package.json +1 -1
  180. package/pyproject.toml +5 -1
  181. package/tui/__pycache__/about.cpython-314.pyc +0 -0
  182. package/tui/__pycache__/agents.cpython-314.pyc +0 -0
  183. package/tui/__pycache__/app.cpython-313.pyc +0 -0
  184. package/tui/__pycache__/app.cpython-314.pyc +0 -0
  185. package/tui/__pycache__/danger.cpython-314.pyc +0 -0
  186. package/tui/__pycache__/messages.cpython-314.pyc +0 -0
  187. package/tui/__pycache__/path_complete.cpython-314.pyc +0 -0
  188. package/tui/__pycache__/paths.cpython-314.pyc +0 -0
  189. package/tui/__pycache__/session_tracker.cpython-314.pyc +0 -0
  190. package/tui/__pycache__/settings_schema.cpython-314.pyc +0 -0
  191. package/tui/acp/__pycache__/agent.cpython-314.pyc +0 -0
  192. package/tui/acp/__pycache__/api.cpython-314.pyc +0 -0
  193. package/tui/acp/__pycache__/messages.cpython-314.pyc +0 -0
  194. package/tui/acp/__pycache__/prompt.cpython-314.pyc +0 -0
  195. package/tui/acp/__pycache__/protocol.cpython-314.pyc +0 -0
  196. package/tui/acp/agent.py +125 -58
  197. package/tui/acp/api.py +12 -0
  198. package/tui/acp/messages.py +3 -1
  199. package/tui/acp/prompt.py +0 -57
  200. package/tui/acp/protocol.py +6 -0
  201. package/tui/agents.py +8 -7
  202. package/tui/app.py +11 -33
  203. package/tui/data/agents/ampcode.com.toml +1 -0
  204. package/tui/data/agents/augmentcode.com.toml +1 -0
  205. package/tui/data/agents/cdh.cloud-dev-harness.toml +3 -2
  206. package/tui/data/agents/crowai.dev.toml +1 -0
  207. package/tui/data/agents/deepagents.langchain.com +1 -0
  208. package/tui/data/agents/docker.com.toml +1 -0
  209. package/tui/data/agents/goose.ai.toml +1 -0
  210. package/tui/data/agents/inference.huggingface.co.toml +1 -1
  211. package/tui/data/agents/kiro.dev.toml +1 -0
  212. package/tui/data/agents/onecode.dev.toml +22 -0
  213. package/tui/data/agents/openclaw.ai.toml +1 -1
  214. package/tui/data/agents/openhands.dev.toml +1 -0
  215. package/tui/data/agents/stakpak.dev.toml +1 -0
  216. package/tui/data/agents/vibe.mistral.ai.toml +1 -0
  217. package/tui/data/agents/vtcode.dev.toml +1 -0
  218. package/tui/messages.py +2 -0
  219. package/tui/path_complete.py +1 -1
  220. package/tui/paths.py +16 -0
  221. package/tui/screens/__pycache__/component_picker.cpython-314.pyc +0 -0
  222. package/tui/screens/__pycache__/diff_screen.cpython-314.pyc +0 -0
  223. package/tui/screens/__pycache__/log.cpython-314.pyc +0 -0
  224. package/tui/screens/__pycache__/main.cpython-313.pyc +0 -0
  225. package/tui/screens/__pycache__/main.cpython-314.pyc +0 -0
  226. package/tui/screens/__pycache__/permissions.cpython-314.pyc +0 -0
  227. package/tui/screens/__pycache__/projects_app.cpython-314.pyc +0 -0
  228. package/tui/screens/__pycache__/projects_screen.cpython-314.pyc +0 -0
  229. package/tui/screens/__pycache__/sessions.cpython-314.pyc +0 -0
  230. package/tui/screens/__pycache__/store.cpython-314.pyc +0 -0
  231. package/tui/screens/__pycache__/tool_content_screen.cpython-314.pyc +0 -0
  232. package/tui/screens/component_picker.py +35 -15
  233. package/tui/screens/diff_screen.py +84 -0
  234. package/tui/screens/log.py +25 -25
  235. package/tui/screens/main.py +48 -26
  236. package/tui/screens/projects.tcss +5 -1
  237. package/tui/screens/projects_app.py +6 -6
  238. package/tui/screens/projects_screen.py +19 -39
  239. package/tui/screens/sessions.py +3 -5
  240. package/tui/screens/store.py +1 -1
  241. package/tui/session_tracker.py +3 -0
  242. package/tui/settings_schema.py +2 -2
  243. package/tui/visuals/__pycache__/columns.cpython-314.pyc +0 -0
  244. package/tui/visuals/columns.py +1 -2
  245. package/tui/widgets/__pycache__/agent_response.cpython-314.pyc +0 -0
  246. package/tui/widgets/__pycache__/agent_thought.cpython-314.pyc +0 -0
  247. package/tui/widgets/__pycache__/conversation.cpython-314.pyc +0 -0
  248. package/tui/widgets/__pycache__/diff_view.cpython-314.pyc +0 -0
  249. package/tui/widgets/__pycache__/load_more.cpython-314.pyc +0 -0
  250. package/tui/widgets/__pycache__/modified_files.cpython-314.pyc +0 -0
  251. package/tui/widgets/__pycache__/plan.cpython-314.pyc +0 -0
  252. package/tui/widgets/__pycache__/project_grid_select.cpython-314.pyc +0 -0
  253. package/tui/widgets/__pycache__/session_grid_select.cpython-314.pyc +0 -0
  254. package/tui/widgets/__pycache__/shell_result.cpython-314.pyc +0 -0
  255. package/tui/widgets/__pycache__/side_bar.cpython-314.pyc +0 -0
  256. package/tui/widgets/__pycache__/subagent.cpython-314.pyc +0 -0
  257. package/tui/widgets/__pycache__/subagent_screen.cpython-314.pyc +0 -0
  258. package/tui/widgets/__pycache__/terminal.cpython-314.pyc +0 -0
  259. package/tui/widgets/__pycache__/tool_call.cpython-314.pyc +0 -0
  260. package/tui/widgets/agent_response.py +0 -1
  261. package/tui/widgets/agent_thought.py +0 -1
  262. package/tui/widgets/conversation.py +157 -14
  263. package/tui/widgets/diff_view.py +10 -0
  264. package/tui/widgets/load_more.py +24 -0
  265. package/tui/widgets/modified_files.py +173 -105
  266. package/tui/widgets/plan.py +1 -1
  267. package/tui/widgets/project_grid_select.py +9 -2
  268. package/tui/widgets/session_grid_select.py +6 -0
  269. package/tui/widgets/side_bar.py +10 -0
  270. package/tui/widgets/subagent.py +92 -58
  271. package/tui/widgets/subagent_screen.py +638 -115
  272. package/tui/widgets/terminal.py +1 -2
  273. package/tui/widgets/terminal_tool.py +11 -2
  274. package/tui/widgets/tool_call.py +35 -2
  275. package/cdh/__pycache__/__init__.cpython-313.pyc +0 -0
  276. package/cdh/__pycache__/__main__.cpython-314.pyc +0 -0
  277. package/cdh/__pycache__/scaffold.cpython-313.pyc +0 -0
  278. package/onecode/__pycache__/mock_data.cpython-314.pyc +0 -0
  279. package/onecode/agent/__pycache__/cdh_agent_acp.cpython-313.pyc +0 -0
  280. package/onecode/agent/__pycache__/cdh_agent_acp.cpython-314.pyc +0 -0
  281. package/onecode/agent/__pycache__/harness_skill.cpython-314.pyc +0 -0
  282. package/onecode/agent/tools/__pycache__/task_tools.cpython-314.pyc +0 -0
  283. package/onecode/codebase/__pycache__/config.cpython-314.pyc +0 -0
  284. package/onecode/memory/offload.py +0 -114
  285. package/onecode/memory/symbolic.py +0 -164
  286. package/onecode/models/providers/__pycache__/mock_provider.cpython-314.pyc +0 -0
  287. package/onecode/tasks/__pycache__/__init__.cpython-314.pyc +0 -0
  288. package/onecode/tasks/__pycache__/manager.cpython-314.pyc +0 -0
  289. package/onecode/tasks/__pycache__/models.cpython-314.pyc +0 -0
  290. package/tui/__pycache__/cli.cpython-314.pyc +0 -0
  291. package/tui/screens/__pycache__/settings.cpython-314.pyc +0 -0
  292. package/tui/widgets/__pycache__/conversation.cpython-313.pyc +0 -0
  293. package/tui/widgets/__pycache__/terminal.cpython-313.pyc +0 -0
  294. package/tui/widgets/__pycache__/tool_call.cpython-313.pyc +0 -0
@@ -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 ensure_dirs, load_config, save_config
6
+ from onecode.config import load_config, save_config
8
7
 
9
- LOG_DIR = Path.home() / ".cdh" / "logs"
10
- LOG_FILE = LOG_DIR / "cdh.log"
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, CodebaseConfig
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")
@@ -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
- for fpath in files:
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 os
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, Session
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
- db_dir = project_dir / ".cdh" / "codebase"
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)
@@ -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 enable 2` — enable the skill at index 2 from the list\n"
327
- "- `/onecode:skill add my-skill` — scaffold a new skill named `my-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
  )