@scemoon/cdh 1.0.4 → 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.
- 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 +14 -3
- 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/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,19 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def load_project_doc(workspace_root: Path) -> str:
|
|
7
|
+
"""Read ``AGENTS.md`` at the project root if present.
|
|
8
|
+
|
|
9
|
+
Convention mirrors ``AGENTS.md`` / ``CLAUDE.md``: exactly one file at
|
|
10
|
+
the workspace root that all AI agents must read. Unlike skills,
|
|
11
|
+
this is not registered — it's injected directly as project context.
|
|
12
|
+
"""
|
|
13
|
+
path = workspace_root.resolve() / "AGENTS.md"
|
|
14
|
+
if not path.exists():
|
|
15
|
+
return ""
|
|
16
|
+
try:
|
|
17
|
+
return path.read_text(encoding="utf-8")
|
|
18
|
+
except Exception:
|
|
19
|
+
return ""
|
package/onecode/agent/session.py
CHANGED
|
@@ -72,8 +72,23 @@ class AgentSession:
|
|
|
72
72
|
self._data.id = session_id
|
|
73
73
|
|
|
74
74
|
def _default_storage_path(self) -> Path:
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
cdh_sessions = Path.home() / ".cdh" / "sessions"
|
|
76
|
+
# One-time self-heal: move sessions incorrectly saved to ~/.onecode/sessions/
|
|
77
|
+
# back to the cdh platform-level directory (B mapping mode).
|
|
78
|
+
onecode_sessions = Path.home() / ".onecode" / "sessions"
|
|
79
|
+
marker = cdh_sessions / ".migrated_from_onecode"
|
|
80
|
+
if not marker.exists() and onecode_sessions.exists():
|
|
81
|
+
try:
|
|
82
|
+
cdh_sessions.mkdir(parents=True, exist_ok=True)
|
|
83
|
+
for f in list(onecode_sessions.glob("*.json"))[:250]:
|
|
84
|
+
dst = cdh_sessions / f.name
|
|
85
|
+
if not dst.exists():
|
|
86
|
+
import shutil
|
|
87
|
+
shutil.move(str(f), str(dst))
|
|
88
|
+
marker.write_text("migrated", encoding="utf-8")
|
|
89
|
+
except Exception as e:
|
|
90
|
+
logger.warning("Failed to migrate onecode sessions to cdh: %s", e)
|
|
91
|
+
return cdh_sessions
|
|
77
92
|
|
|
78
93
|
@property
|
|
79
94
|
def id(self) -> str:
|
|
@@ -115,7 +130,6 @@ class AgentSession:
|
|
|
115
130
|
if len(self._data.messages) <= 2:
|
|
116
131
|
return
|
|
117
132
|
system_msgs = [m for m in self._data.messages if m.get("role") == "system"]
|
|
118
|
-
other_msgs = [m for m in self._data.messages if m.get("role") != "system"]
|
|
119
133
|
self._data.messages = system_msgs + [
|
|
120
134
|
{"role": "system", "content": f"[Previous context summarized]\n{summary}"}
|
|
121
135
|
]
|
|
@@ -5,9 +5,8 @@ import json
|
|
|
5
5
|
import os
|
|
6
6
|
import shutil
|
|
7
7
|
import tarfile
|
|
8
|
-
import tempfile
|
|
9
8
|
import uuid
|
|
10
|
-
from dataclasses import dataclass
|
|
9
|
+
from dataclasses import dataclass
|
|
11
10
|
from datetime import datetime, timezone
|
|
12
11
|
from pathlib import Path
|
|
13
12
|
from typing import Optional
|
|
@@ -25,8 +24,8 @@ class SnapshotInfo:
|
|
|
25
24
|
|
|
26
25
|
class SnapshotManager:
|
|
27
26
|
def __init__(self, base_path: Optional[Path] = None):
|
|
28
|
-
from onecode.config import
|
|
29
|
-
self.base_path = base_path or (
|
|
27
|
+
from onecode.config import ONECODE_DIR
|
|
28
|
+
self.base_path = base_path or (ONECODE_DIR / "snapshots")
|
|
30
29
|
self.base_path.mkdir(parents=True, exist_ok=True)
|
|
31
30
|
|
|
32
31
|
def create(
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import json
|
|
4
3
|
from typing import Any
|
|
5
4
|
|
|
6
5
|
from onecode.agent.tools.protocol import ToolResult
|
|
7
|
-
from onecode.agent.tools.registry import ToolRegistry, ToolSpec
|
|
6
|
+
from onecode.agent.tools.registry import Tool, ToolRegistry, ToolSpec
|
|
8
7
|
|
|
9
8
|
|
|
10
|
-
class AgentTool:
|
|
9
|
+
class AgentTool(Tool):
|
|
11
10
|
def __init__(self, registry: ToolRegistry, permission_checker=None):
|
|
12
11
|
self._registry = registry
|
|
13
12
|
self._permission_checker = permission_checker
|
|
@@ -76,7 +75,7 @@ class AgentTool:
|
|
|
76
75
|
|
|
77
76
|
|
|
78
77
|
|
|
79
|
-
class TaskTool:
|
|
78
|
+
class TaskTool(Tool):
|
|
80
79
|
VALID_AGENT_TYPES: tuple[str, ...] = (
|
|
81
80
|
"general", "explore", "scout",
|
|
82
81
|
"build", "plan", "solo",
|
|
@@ -88,7 +87,7 @@ class TaskTool:
|
|
|
88
87
|
def spec(self) -> ToolSpec:
|
|
89
88
|
return ToolSpec(
|
|
90
89
|
name="Spawn",
|
|
91
|
-
description="Delegate a subtask to a specialized subagent. Use for
|
|
90
|
+
description="Delegate a subtask to a specialized subagent. Use for complex multi-step work or work that benefits from an isolated context.",
|
|
92
91
|
input_schema={
|
|
93
92
|
"type": "object",
|
|
94
93
|
"properties": {
|
|
@@ -118,7 +117,6 @@ class TaskTool:
|
|
|
118
117
|
is_error=True,
|
|
119
118
|
)
|
|
120
119
|
import asyncio
|
|
121
|
-
import concurrent.futures
|
|
122
120
|
try:
|
|
123
121
|
loop = asyncio.get_event_loop()
|
|
124
122
|
if loop.is_running():
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import re
|
|
4
|
-
from pathlib import Path
|
|
5
4
|
from typing import Any
|
|
6
5
|
|
|
7
6
|
from onecode.agent.tools.file_ops import FileOps
|
|
8
7
|
from onecode.agent.tools.protocol import ToolResult
|
|
9
|
-
from onecode.agent.tools.registry import ToolSpec
|
|
8
|
+
from onecode.agent.tools.registry import Tool, ToolSpec
|
|
10
9
|
|
|
11
10
|
|
|
12
|
-
class ApplyPatchTool:
|
|
11
|
+
class ApplyPatchTool(Tool):
|
|
13
12
|
def __init__(self, file_ops: FileOps):
|
|
14
13
|
self._file_ops = file_ops
|
|
15
14
|
|
|
@@ -43,7 +42,6 @@ class ApplyPatchTool:
|
|
|
43
42
|
results = []
|
|
44
43
|
current_file: str | None = None
|
|
45
44
|
current_content: list[str] = []
|
|
46
|
-
patch_type = "update"
|
|
47
45
|
|
|
48
46
|
lines = patch.split("\n")
|
|
49
47
|
i = 0
|
|
@@ -61,7 +59,6 @@ class ApplyPatchTool:
|
|
|
61
59
|
results.append(result)
|
|
62
60
|
current_file = add_match.group(1).strip()
|
|
63
61
|
current_content = []
|
|
64
|
-
patch_type = "add"
|
|
65
62
|
|
|
66
63
|
elif update_match:
|
|
67
64
|
if current_file and current_content:
|
|
@@ -69,7 +66,6 @@ class ApplyPatchTool:
|
|
|
69
66
|
results.append(result)
|
|
70
67
|
current_file = update_match.group(1).strip()
|
|
71
68
|
current_content = []
|
|
72
|
-
patch_type = "update"
|
|
73
69
|
|
|
74
70
|
elif move_match:
|
|
75
71
|
target = move_match.group(1).strip()
|
|
@@ -77,7 +73,6 @@ class ApplyPatchTool:
|
|
|
77
73
|
result = self._move_file(current_file, target)
|
|
78
74
|
results.append(result)
|
|
79
75
|
current_file = target
|
|
80
|
-
patch_type = "move"
|
|
81
76
|
|
|
82
77
|
elif delete_match:
|
|
83
78
|
target = delete_match.group(1).strip()
|
|
@@ -85,7 +80,6 @@ class ApplyPatchTool:
|
|
|
85
80
|
results.append(result)
|
|
86
81
|
current_file = None
|
|
87
82
|
current_content = []
|
|
88
|
-
patch_type = "delete"
|
|
89
83
|
|
|
90
84
|
else:
|
|
91
85
|
if current_file is not None:
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import re
|
|
4
|
-
from
|
|
5
|
-
from typing import Any, Optional
|
|
4
|
+
from typing import Any, Callable
|
|
6
5
|
|
|
7
6
|
from onecode.agent.tools.file_ops import ShellTool
|
|
8
7
|
from onecode.agent.tools.protocol import ToolResult
|
|
9
|
-
from onecode.agent.tools.registry import ToolSpec
|
|
8
|
+
from onecode.agent.tools.registry import Tool, ToolSpec
|
|
10
9
|
|
|
11
10
|
|
|
12
11
|
_DANGEROUS_PATTERNS = [
|
|
@@ -21,7 +20,7 @@ _DANGEROUS_PATTERNS = [
|
|
|
21
20
|
]
|
|
22
21
|
|
|
23
22
|
|
|
24
|
-
class BashTool:
|
|
23
|
+
class BashTool(Tool):
|
|
25
24
|
def __init__(self, shell: ShellTool):
|
|
26
25
|
self._shell = shell
|
|
27
26
|
|
|
@@ -45,21 +44,42 @@ class BashTool:
|
|
|
45
44
|
command = tool_input.get("command", "")
|
|
46
45
|
timeout = tool_input.get("timeout", 60)
|
|
47
46
|
|
|
47
|
+
error = self._validate(command)
|
|
48
|
+
if error:
|
|
49
|
+
return error
|
|
50
|
+
|
|
51
|
+
result = self._shell.exec(command, timeout=timeout)
|
|
52
|
+
return self._to_tool_result(result, tool_input)
|
|
53
|
+
|
|
54
|
+
async def run_async(
|
|
55
|
+
self, tool_input: dict[str, Any],
|
|
56
|
+
cancel_check: Callable[[], bool] | None = None,
|
|
57
|
+
) -> ToolResult:
|
|
58
|
+
command = tool_input.get("command", "")
|
|
59
|
+
timeout = tool_input.get("timeout", 60)
|
|
60
|
+
|
|
61
|
+
error = self._validate(command)
|
|
62
|
+
if error:
|
|
63
|
+
return error
|
|
64
|
+
|
|
65
|
+
result = await self._shell.exec_async(command, timeout=timeout, cancel_check=cancel_check)
|
|
66
|
+
return self._to_tool_result(result, tool_input)
|
|
67
|
+
|
|
68
|
+
def _validate(self, command: str) -> ToolResult | None:
|
|
48
69
|
if not isinstance(command, str) or not command.strip():
|
|
49
70
|
return ToolResult(name="Bash", output="command must be a non-empty string", is_error=True, content_type="text")
|
|
50
71
|
if "\x00" in command:
|
|
51
72
|
return ToolResult(name="Bash", output="command contains NUL byte", is_error=True, content_type="text")
|
|
52
|
-
|
|
53
73
|
for pat in _DANGEROUS_PATTERNS:
|
|
54
74
|
if pat.search(command):
|
|
55
75
|
return ToolResult(name="Bash", output="refusing to run potentially dangerous command", is_error=True, content_type="text")
|
|
76
|
+
return None
|
|
56
77
|
|
|
57
|
-
|
|
78
|
+
def _to_tool_result(self, result: dict, tool_input: dict) -> ToolResult:
|
|
58
79
|
is_error = not result.get("success", True)
|
|
59
80
|
stdout = result.get("stdout", "") or ""
|
|
60
81
|
stderr = result.get("stderr", "") or ""
|
|
61
82
|
error_msg = result.get("error", "") or ""
|
|
62
|
-
|
|
63
83
|
formatted = self._format_bash_output(stdout, stderr, error_msg, is_error)
|
|
64
84
|
return ToolResult(
|
|
65
85
|
name="Bash",
|
|
@@ -75,17 +95,17 @@ class BashTool:
|
|
|
75
95
|
|
|
76
96
|
Stderr is rendered first when present so failures are visible,
|
|
77
97
|
the underlying ``error`` string is included for non-zero exits /
|
|
78
|
-
transport failures, and
|
|
79
|
-
|
|
98
|
+
transport failures, and the result is fenced so the TUI renders
|
|
99
|
+
it as a code block with bash syntax highlighting.
|
|
80
100
|
"""
|
|
81
101
|
parts: list[str] = []
|
|
82
102
|
if error.strip():
|
|
83
103
|
parts.append(f"[error] {error.strip()}")
|
|
84
104
|
if stderr.strip():
|
|
85
|
-
parts.append(f"
|
|
105
|
+
parts.append(f"[stderr]\n{stderr.rstrip()}")
|
|
86
106
|
if stdout.strip():
|
|
87
|
-
parts.append(
|
|
107
|
+
parts.append(stdout.rstrip())
|
|
88
108
|
if not parts:
|
|
89
109
|
return "(no output)" if not is_error else "(failed with no output)"
|
|
90
|
-
return "\n\n".join(parts)
|
|
110
|
+
return "```bash\n" + "\n\n".join(parts) + "\n```"
|
|
91
111
|
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import json
|
|
4
3
|
from typing import Any
|
|
5
4
|
|
|
6
5
|
from onecode.agent.tools.protocol import ToolResult
|
|
7
|
-
from onecode.agent.tools.registry import ToolRegistry, ToolSpec
|
|
6
|
+
from onecode.agent.tools.registry import Tool, ToolRegistry, ToolSpec
|
|
8
7
|
|
|
9
8
|
|
|
10
|
-
class SendMessageTool:
|
|
9
|
+
class SendMessageTool(Tool):
|
|
11
10
|
def __init__(self):
|
|
12
11
|
self.last_message: str = ""
|
|
13
12
|
|
|
@@ -70,7 +69,7 @@ _QUESTION_SCHEMA = {
|
|
|
70
69
|
}
|
|
71
70
|
|
|
72
71
|
|
|
73
|
-
class AskUserTool:
|
|
72
|
+
class AskUserTool(Tool):
|
|
74
73
|
def spec(self) -> ToolSpec:
|
|
75
74
|
return ToolSpec(
|
|
76
75
|
name="AskUser",
|
|
@@ -118,7 +117,7 @@ class AskUserTool:
|
|
|
118
117
|
|
|
119
118
|
|
|
120
119
|
|
|
121
|
-
class ToolSearchTool:
|
|
120
|
+
class ToolSearchTool(Tool):
|
|
122
121
|
def __init__(self, registry: ToolRegistry):
|
|
123
122
|
self._registry = registry
|
|
124
123
|
|
|
@@ -4,13 +4,13 @@ import logging
|
|
|
4
4
|
from typing import Any
|
|
5
5
|
|
|
6
6
|
from onecode.agent.tools.protocol import ToolResult
|
|
7
|
-
from onecode.agent.tools.registry import ToolSpec
|
|
7
|
+
from onecode.agent.tools.registry import Tool, ToolSpec
|
|
8
8
|
from onecode.config import GlobalConfig
|
|
9
9
|
|
|
10
10
|
logger = logging.getLogger("onecode.tools.config")
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
class ConfigReadTool:
|
|
13
|
+
class ConfigReadTool(Tool):
|
|
14
14
|
"""Read configuration values accessible to the LLM (Clawd-Code pattern)."""
|
|
15
15
|
|
|
16
16
|
def __init__(self, config: GlobalConfig):
|
|
@@ -64,7 +64,7 @@ class ConfigReadTool:
|
|
|
64
64
|
|
|
65
65
|
|
|
66
66
|
|
|
67
|
-
class ConfigWriteTool:
|
|
67
|
+
class ConfigWriteTool(Tool):
|
|
68
68
|
"""Write configuration values accessible to the LLM (Clawd-Code pattern)."""
|
|
69
69
|
|
|
70
70
|
def __init__(self, config: GlobalConfig, save_fn=None):
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
-
import json
|
|
5
4
|
from dataclasses import dataclass, field
|
|
6
5
|
from datetime import datetime, timedelta
|
|
7
6
|
from typing import Any, Callable
|
|
8
7
|
|
|
9
8
|
from onecode.agent.tools.protocol import ToolResult
|
|
10
|
-
from onecode.agent.tools.registry import ToolSpec
|
|
9
|
+
from onecode.agent.tools.registry import Tool, ToolSpec
|
|
11
10
|
|
|
12
11
|
|
|
13
12
|
@dataclass
|
|
@@ -95,7 +94,7 @@ class CronScheduler:
|
|
|
95
94
|
self._task = None
|
|
96
95
|
|
|
97
96
|
|
|
98
|
-
class CronCreateTool:
|
|
97
|
+
class CronCreateTool(Tool):
|
|
99
98
|
"""Create a scheduled cron job (Clawd-Code pattern)."""
|
|
100
99
|
|
|
101
100
|
def __init__(self, scheduler: CronScheduler):
|
|
@@ -131,7 +130,7 @@ class CronCreateTool:
|
|
|
131
130
|
|
|
132
131
|
|
|
133
132
|
|
|
134
|
-
class CronListTool:
|
|
133
|
+
class CronListTool(Tool):
|
|
135
134
|
"""List all cron jobs."""
|
|
136
135
|
|
|
137
136
|
def __init__(self, scheduler: CronScheduler):
|
|
@@ -152,7 +151,7 @@ class CronListTool:
|
|
|
152
151
|
|
|
153
152
|
|
|
154
153
|
|
|
155
|
-
class CronRemoveTool:
|
|
154
|
+
class CronRemoveTool(Tool):
|
|
156
155
|
"""Remove a cron job."""
|
|
157
156
|
|
|
158
157
|
def __init__(self, scheduler: CronScheduler):
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import asyncio
|
|
4
4
|
import subprocess
|
|
5
5
|
from pathlib import Path
|
|
6
|
-
from typing import Optional
|
|
6
|
+
from typing import Callable, Optional
|
|
7
7
|
|
|
8
8
|
from onecode.agent.permissions import PermissionChecker, PermissionSet, create_safe_permission_set
|
|
9
|
-
from onecode.agent.tools.sandbox import
|
|
9
|
+
from onecode.agent.tools.sandbox import create_sandbox
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class FileOps:
|
|
@@ -116,6 +116,22 @@ class FileOps:
|
|
|
116
116
|
except Exception:
|
|
117
117
|
return []
|
|
118
118
|
|
|
119
|
+
async def grep_async(self, pattern: str, include: Optional[str] = None, path: Optional[str] = None) -> list[str]:
|
|
120
|
+
base = self._resolve(path) if path else self.workspace
|
|
121
|
+
cmd = ["grep", "-rn", pattern, str(base)]
|
|
122
|
+
if include:
|
|
123
|
+
cmd.extend(["--include", include])
|
|
124
|
+
try:
|
|
125
|
+
process = await asyncio.create_subprocess_exec(
|
|
126
|
+
*cmd,
|
|
127
|
+
stdout=asyncio.subprocess.PIPE,
|
|
128
|
+
stderr=asyncio.subprocess.PIPE,
|
|
129
|
+
)
|
|
130
|
+
stdout, _ = await asyncio.wait_for(process.communicate(), timeout=30)
|
|
131
|
+
return stdout.decode("utf-8", errors="replace").split("\n")
|
|
132
|
+
except Exception:
|
|
133
|
+
return []
|
|
134
|
+
|
|
119
135
|
def list(self, path: str = ".") -> list[dict]:
|
|
120
136
|
p = self._resolve(path)
|
|
121
137
|
if not p.exists():
|
|
@@ -176,6 +192,24 @@ class ShellTool:
|
|
|
176
192
|
|
|
177
193
|
return self._sandbox.exec(cmd, timeout=timeout)
|
|
178
194
|
|
|
195
|
+
async def exec_async(
|
|
196
|
+
self, cmd: str,
|
|
197
|
+
cwd: Optional[str] = None,
|
|
198
|
+
timeout: int = 60,
|
|
199
|
+
cancel_check: Callable[[], bool] | None = None,
|
|
200
|
+
) -> dict:
|
|
201
|
+
result = self._checker.check_command(cmd)
|
|
202
|
+
if result.value == "deny":
|
|
203
|
+
return {"success": False, "error": "Command not allowed", "requires_approval": False}
|
|
204
|
+
if result.value == "ask":
|
|
205
|
+
return {"success": False, "error": "Command requires approval", "requires_approval": True}
|
|
206
|
+
|
|
207
|
+
work_dir = Path(cwd) if cwd else self.workspace
|
|
208
|
+
if not work_dir.is_relative_to(self.workspace.resolve()):
|
|
209
|
+
return {"success": False, "error": "CWD outside workspace"}
|
|
210
|
+
|
|
211
|
+
return await self._sandbox.exec_async(cmd, timeout=timeout, cancel_check=cancel_check)
|
|
212
|
+
|
|
179
213
|
|
|
180
214
|
class ToolFactory:
|
|
181
215
|
@staticmethod
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from
|
|
4
|
-
from typing import Any, Optional
|
|
3
|
+
from typing import Any
|
|
5
4
|
|
|
6
5
|
from onecode.agent.tools.file_ops import FileOps
|
|
7
6
|
from onecode.agent.tools.protocol import ToolResult
|
|
8
|
-
from onecode.agent.tools.registry import ToolSpec
|
|
7
|
+
from onecode.agent.tools.registry import Tool, ToolSpec
|
|
9
8
|
|
|
10
9
|
|
|
11
|
-
class ReadTool:
|
|
10
|
+
class ReadTool(Tool):
|
|
12
11
|
def __init__(self, file_ops: FileOps):
|
|
13
12
|
self._file_ops = file_ops
|
|
14
13
|
|
|
@@ -39,7 +38,7 @@ class ReadTool:
|
|
|
39
38
|
|
|
40
39
|
|
|
41
40
|
|
|
42
|
-
class WriteTool:
|
|
41
|
+
class WriteTool(Tool):
|
|
43
42
|
def __init__(self, file_ops: FileOps):
|
|
44
43
|
self._file_ops = file_ops
|
|
45
44
|
|
|
@@ -66,7 +65,7 @@ class WriteTool:
|
|
|
66
65
|
|
|
67
66
|
|
|
68
67
|
|
|
69
|
-
class EditTool:
|
|
68
|
+
class EditTool(Tool):
|
|
70
69
|
def __init__(self, file_ops: FileOps):
|
|
71
70
|
self._file_ops = file_ops
|
|
72
71
|
|
|
@@ -95,7 +94,7 @@ class EditTool:
|
|
|
95
94
|
|
|
96
95
|
|
|
97
96
|
|
|
98
|
-
class InsertTool:
|
|
97
|
+
class InsertTool(Tool):
|
|
99
98
|
def __init__(self, file_ops: FileOps):
|
|
100
99
|
self._file_ops = file_ops
|
|
101
100
|
|
|
@@ -124,7 +123,7 @@ class InsertTool:
|
|
|
124
123
|
|
|
125
124
|
|
|
126
125
|
|
|
127
|
-
class UndoEditTool:
|
|
126
|
+
class UndoEditTool(Tool):
|
|
128
127
|
def __init__(self, file_ops: FileOps):
|
|
129
128
|
self._file_ops = file_ops
|
|
130
129
|
|
|
@@ -149,7 +148,7 @@ class UndoEditTool:
|
|
|
149
148
|
|
|
150
149
|
|
|
151
150
|
|
|
152
|
-
class GlobTool:
|
|
151
|
+
class GlobTool(Tool):
|
|
153
152
|
def __init__(self, file_ops: FileOps):
|
|
154
153
|
self._file_ops = file_ops
|
|
155
154
|
|
|
@@ -174,7 +173,7 @@ class GlobTool:
|
|
|
174
173
|
|
|
175
174
|
|
|
176
175
|
|
|
177
|
-
class GrepTool:
|
|
176
|
+
class GrepTool(Tool):
|
|
178
177
|
def __init__(self, file_ops: FileOps):
|
|
179
178
|
self._file_ops = file_ops
|
|
180
179
|
|
|
@@ -201,7 +200,7 @@ class GrepTool:
|
|
|
201
200
|
|
|
202
201
|
|
|
203
202
|
|
|
204
|
-
class ListTool:
|
|
203
|
+
class ListTool(Tool):
|
|
205
204
|
def __init__(self, file_ops: FileOps):
|
|
206
205
|
self._file_ops = file_ops
|
|
207
206
|
|
|
@@ -5,10 +5,10 @@ from pathlib import Path
|
|
|
5
5
|
from typing import Any
|
|
6
6
|
|
|
7
7
|
from onecode.agent.tools.protocol import ToolResult
|
|
8
|
-
from onecode.agent.tools.registry import ToolSpec
|
|
8
|
+
from onecode.agent.tools.registry import Tool, ToolSpec
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
class WorktreeTool:
|
|
11
|
+
class WorktreeTool(Tool):
|
|
12
12
|
"""Manage git worktrees (Clawd-Code pattern)."""
|
|
13
13
|
|
|
14
14
|
def __init__(self, workspace_root: Path | None = None):
|
|
@@ -6,7 +6,7 @@ from pathlib import Path
|
|
|
6
6
|
from typing import Any
|
|
7
7
|
|
|
8
8
|
from onecode.agent.tools.protocol import ToolResult
|
|
9
|
-
from onecode.agent.tools.registry import ToolSpec
|
|
9
|
+
from onecode.agent.tools.registry import Tool, ToolSpec
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class LSPClient:
|
|
@@ -263,7 +263,7 @@ class LSPClient:
|
|
|
263
263
|
self._process = None
|
|
264
264
|
|
|
265
265
|
|
|
266
|
-
class LSPTool:
|
|
266
|
+
class LSPTool(Tool):
|
|
267
267
|
def __init__(self):
|
|
268
268
|
self._servers: dict[str, LSPClient] = {}
|
|
269
269
|
|
|
@@ -3,11 +3,11 @@ from __future__ import annotations
|
|
|
3
3
|
from typing import Any
|
|
4
4
|
|
|
5
5
|
from onecode.agent.tools.protocol import ToolResult
|
|
6
|
-
from onecode.agent.tools.registry import ToolSpec
|
|
6
|
+
from onecode.agent.tools.registry import Tool, ToolSpec
|
|
7
7
|
from onecode.mcp.manager import MCPManager
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
class MCPTool:
|
|
10
|
+
class MCPTool(Tool):
|
|
11
11
|
"""Call a tool from a connected MCP server (Clawd-Code pattern)."""
|
|
12
12
|
|
|
13
13
|
def __init__(self, mcp_manager: MCPManager):
|
|
@@ -42,7 +42,6 @@ class MCPTool:
|
|
|
42
42
|
try:
|
|
43
43
|
loop = asyncio.get_event_loop()
|
|
44
44
|
if loop.is_running():
|
|
45
|
-
import threading
|
|
46
45
|
future = asyncio.run_coroutine_threadsafe(
|
|
47
46
|
self._mcp.call_tool(server, tool_name, args), loop
|
|
48
47
|
)
|
|
@@ -59,7 +58,7 @@ class MCPTool:
|
|
|
59
58
|
|
|
60
59
|
|
|
61
60
|
|
|
62
|
-
class MCPResourcesTool:
|
|
61
|
+
class MCPResourcesTool(Tool):
|
|
63
62
|
"""Access resources from a connected MCP server."""
|
|
64
63
|
|
|
65
64
|
def __init__(self, mcp_manager: MCPManager):
|
|
@@ -104,7 +103,6 @@ class MCPResourcesTool:
|
|
|
104
103
|
try:
|
|
105
104
|
loop = asyncio.get_event_loop()
|
|
106
105
|
if loop.is_running():
|
|
107
|
-
import threading
|
|
108
106
|
if action == "list":
|
|
109
107
|
future = asyncio.run_coroutine_threadsafe(
|
|
110
108
|
client._send_request("resources/list", {}), loop
|