feat(tools): add grep and workspace profile, fix write path

- Add grep_tool: ripgrep with Python fallback; avoid --json with -l/-c.
- Add workspace_profile_tool: scan, languages, tests, packages, git, CI hints; tests.
- write_file: resolve relative paths via workspace root (no data/workspace prefix).
- Update path guard and local public tool tests for new write behavior.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-05-13 23:02:52 +08:00
parent 48190afbc1
commit 2b32d11f43
6 changed files with 1019 additions and 21 deletions

View file

@ -103,7 +103,7 @@ class WorkspacePathGuardTests(unittest.TestCase):
p = resolve_workspace_path(str(f))
self.assertEqual(p, f.resolve())
def test_write_file_relative_path_defaults_to_data_workspace_subdir(self) -> None:
def test_write_file_relative_path_resolves_under_workspace_root(self) -> None:
with mock.patch.dict(
os.environ,
{"OPS_WORKSPACE_ROOT": str(self.root), "OPS_WORKSPACE_EXTRA_ROOTS": "", "OPS_WORKSPACE_ALLOW_ANY_PATH": ""},
@ -114,11 +114,11 @@ class WorkspacePathGuardTests(unittest.TestCase):
with workspace_path_access_scope(None, None):
r = spec.handler({"path": "generated.py", "content": "print('ok')\n", "mode": "overwrite"})
self.assertTrue(r.get("ok"), r)
expected = (self.root / "data" / "workspace" / "generated.py").resolve()
expected = (self.root / "generated.py").resolve()
self.assertEqual(str(expected), str(r.get("path")))
self.assertTrue(expected.exists())
def test_write_file_relative_path_uses_workspace_namespace_scope(self) -> None:
def test_write_file_relative_path_with_write_namespace_scope(self) -> None:
with mock.patch.dict(
os.environ,
{"OPS_WORKSPACE_ROOT": str(self.root), "OPS_WORKSPACE_EXTRA_ROOTS": "", "OPS_WORKSPACE_ALLOW_ANY_PATH": ""},
@ -130,7 +130,7 @@ class WorkspacePathGuardTests(unittest.TestCase):
self.assertEqual(current_workspace_write_namespace(), "ops")
r = spec.handler({"path": "generated.py", "content": "print('ok')\n", "mode": "overwrite"})
self.assertTrue(r.get("ok"), r)
expected = (self.root / "data" / "workspace" / "generated.py").resolve()
expected = (self.root / "generated.py").resolve()
self.assertEqual(str(expected), str(r.get("path")))
self.assertTrue(expected.exists())