ctxora 6.2.1 → 6.2.2
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/README.md +1 -0
- package/README.vi.md +1 -0
- package/bin/ctxora.mjs +1 -1
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/src/harness_context/workspace/roots.py +41 -5
package/README.md
CHANGED
|
@@ -67,6 +67,7 @@ Codex · Claude Code · Cursor · Copilot · MCP clients
|
|
|
67
67
|
### Local context engine
|
|
68
68
|
|
|
69
69
|
- AST-aware chunking for Python, JavaScript, and TypeScript, with bounded fallback chunking for other text formats.
|
|
70
|
+
- Framework-agnostic setup, indexing, retrieval, and MCP startup verified for Python, TypeScript, Flutter, Go, Rust, Java, Kotlin, Swift, PHP, and Ruby repositories.
|
|
70
71
|
- Hybrid lexical and local semantic retrieval using BM25, TF-IDF/LSA, keyword overlap, symbols, and paths.
|
|
71
72
|
- Code dependency graph traversal and graph-augmented context selection.
|
|
72
73
|
- CAG, RAG, hybrid CAG/RAG, long-context, and graph-augmented planning strategies.
|
package/README.vi.md
CHANGED
|
@@ -67,6 +67,7 @@ Codex · Claude Code · Cursor · Copilot · MCP clients
|
|
|
67
67
|
### Local context engine
|
|
68
68
|
|
|
69
69
|
- AST-aware chunking cho Python, JavaScript và TypeScript; fallback chunking có giới hạn cho định dạng text khác.
|
|
70
|
+
- Luồng setup, indexing, retrieval và MCP startup độc lập framework, được kiểm thử với Python, TypeScript, Flutter, Go, Rust, Java, Kotlin, Swift, PHP và Ruby.
|
|
70
71
|
- Hybrid lexical và local semantic retrieval bằng BM25, TF-IDF/LSA, keyword overlap, symbol và path.
|
|
71
72
|
- Code dependency graph và graph-augmented context selection.
|
|
72
73
|
- Các strategy CAG, RAG, hybrid CAG/RAG, long context và graph augmented.
|
package/bin/ctxora.mjs
CHANGED
|
@@ -6,7 +6,7 @@ import { dirname, join, resolve } from "node:path";
|
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
7
|
import { spawnSync } from "node:child_process";
|
|
8
8
|
|
|
9
|
-
const PACKAGE_VERSION = "6.2.
|
|
9
|
+
const PACKAGE_VERSION = "6.2.2";
|
|
10
10
|
const PYTHON_RANGE = "3.10-3.13";
|
|
11
11
|
const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
12
12
|
|
package/package.json
CHANGED
package/pyproject.toml
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import fnmatch
|
|
4
|
+
import os
|
|
4
5
|
from pathlib import Path
|
|
5
6
|
|
|
6
7
|
from harness_context.schemas import HarnessError
|
|
@@ -9,8 +10,11 @@ from harness_context.workspace.policy import WorkspacePolicy
|
|
|
9
10
|
|
|
10
11
|
DEFAULT_DENY = (
|
|
11
12
|
".git", ".hg", ".svn", ".ctxora", ".harness", ".ecc", "node_modules", "vendor", ".venv", "venv",
|
|
12
|
-
"dist", "build", "
|
|
13
|
-
"
|
|
13
|
+
"dist", "build", "out", "target", "coverage", ".dart_tool", ".gradle", "Pods", "DerivedData",
|
|
14
|
+
".build", "obj", ".next", ".nuxt", ".svelte-kit", ".angular", ".turbo", ".parcel-cache",
|
|
15
|
+
".expo", ".wrangler", ".serverless", ".terraform", "oh_modules", ".cache", ".pytest_cache",
|
|
16
|
+
".mypy_cache", ".ruff_cache", ".tox", ".nox", "__pycache__", ".env", ".env.*",
|
|
17
|
+
"*.pem", "*.key", "id_rsa", "id_ed25519", "*.sqlite", "*.sqlite3", "*.db", "*.egg-info",
|
|
14
18
|
)
|
|
15
19
|
|
|
16
20
|
|
|
@@ -53,9 +57,37 @@ class WorkspaceRegistry:
|
|
|
53
57
|
for name in (".gitignore", ".ctxoraignore", ".harnessignore"):
|
|
54
58
|
ignore = root / name
|
|
55
59
|
if ignore.is_file():
|
|
56
|
-
|
|
60
|
+
for line in ignore.read_text("utf-8").splitlines():
|
|
61
|
+
pattern = line.strip()
|
|
62
|
+
if not pattern or pattern.startswith("#") or pattern.startswith("!"):
|
|
63
|
+
continue
|
|
64
|
+
patterns.append(pattern.lstrip("/").rstrip("/"))
|
|
57
65
|
return patterns
|
|
58
66
|
|
|
67
|
+
@staticmethod
|
|
68
|
+
def _ignored(relative: str, path: Path, patterns: list[str]) -> bool:
|
|
69
|
+
parts = path.parts
|
|
70
|
+
for pattern in patterns:
|
|
71
|
+
if relative == pattern or relative.startswith(f"{pattern}/"):
|
|
72
|
+
return True
|
|
73
|
+
if fnmatch.fnmatch(relative, pattern) or fnmatch.fnmatch(relative, f"{pattern}/*"):
|
|
74
|
+
return True
|
|
75
|
+
if any(fnmatch.fnmatch(part, pattern) for part in parts):
|
|
76
|
+
return True
|
|
77
|
+
return False
|
|
78
|
+
|
|
79
|
+
@classmethod
|
|
80
|
+
def _candidate_files(cls, root: Path, patterns: list[str]):
|
|
81
|
+
for current, directories, files in os.walk(root, topdown=True, followlinks=False):
|
|
82
|
+
current_path = Path(current)
|
|
83
|
+
directories[:] = [
|
|
84
|
+
name for name in directories
|
|
85
|
+
if not (current_path / name).is_symlink()
|
|
86
|
+
and not cls._ignored((current_path / name).relative_to(root).as_posix(), current_path / name, patterns)
|
|
87
|
+
]
|
|
88
|
+
for name in files:
|
|
89
|
+
yield current_path / name
|
|
90
|
+
|
|
59
91
|
def files(self, workspace_id: str, paths: list[str]) -> list[Path]:
|
|
60
92
|
policy = self.get(workspace_id)
|
|
61
93
|
selected, total = [], 0
|
|
@@ -64,12 +96,12 @@ class WorkspaceRegistry:
|
|
|
64
96
|
continue
|
|
65
97
|
base = source if source.is_dir() else source.parent
|
|
66
98
|
patterns = self._patterns(base)
|
|
67
|
-
candidates = [source] if source.is_file() else
|
|
99
|
+
candidates = [source] if source.is_file() else self._candidate_files(source, patterns)
|
|
68
100
|
for path in candidates:
|
|
69
101
|
if not path.is_file() or path.is_symlink():
|
|
70
102
|
continue
|
|
71
103
|
relative = path.relative_to(base).as_posix()
|
|
72
|
-
if
|
|
104
|
+
if self._ignored(relative, path, patterns):
|
|
73
105
|
continue
|
|
74
106
|
size = path.stat().st_size
|
|
75
107
|
if size > policy.max_file_bytes:
|
|
@@ -77,6 +109,10 @@ class WorkspaceRegistry:
|
|
|
77
109
|
content = path.read_bytes()
|
|
78
110
|
if b"\x00" in content[:4096] or contains_secret(content):
|
|
79
111
|
continue
|
|
112
|
+
try:
|
|
113
|
+
content.decode("utf-8")
|
|
114
|
+
except UnicodeDecodeError:
|
|
115
|
+
continue
|
|
80
116
|
total += size
|
|
81
117
|
if total > policy.max_total_bytes or len(selected) >= policy.max_files:
|
|
82
118
|
raise HarnessError("workspace_limit", "workspace indexing limits exceeded")
|