ctxora 6.2.0 → 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 +12 -1
- package/README.vi.md +12 -1
- package/assets/ctxora-app-icon.png +0 -0
- package/bin/ctxora.mjs +12 -3
- package/package.json +3 -2
- package/pyproject.toml +1 -1
- package/src/harness_context/workspace/roots.py +41 -5
package/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
+
<a href="https://ctxora-landing.vercel.app/">
|
|
4
|
+
<img src="assets/ctxora-app-icon.png" alt="CTXORA icon" width="128" height="128">
|
|
5
|
+
</a>
|
|
6
|
+
|
|
3
7
|
# CTXORA Engine
|
|
4
8
|
|
|
5
9
|
### Index once. Ground every agent.
|
|
@@ -16,7 +20,7 @@
|
|
|
16
20
|
|
|
17
21
|
**English** · [Tiếng Việt](README.vi.md)
|
|
18
22
|
|
|
19
|
-
[Quick start](#quick-start) · [Installation](#installation) · [Agent skills](#agent-skills) · [CLI](#cli-reference) · [MCP](#mcp-tools) · [Security](#privacy-and-security)
|
|
23
|
+
[Website](https://ctxora-landing.vercel.app/) · [Quick start](#quick-start) · [Installation](#installation) · [Agent skills](#agent-skills) · [CLI](#cli-reference) · [MCP](#mcp-tools) · [Security](#privacy-and-security)
|
|
20
24
|
|
|
21
25
|
</div>
|
|
22
26
|
|
|
@@ -63,6 +67,7 @@ Codex · Claude Code · Cursor · Copilot · MCP clients
|
|
|
63
67
|
### Local context engine
|
|
64
68
|
|
|
65
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.
|
|
66
71
|
- Hybrid lexical and local semantic retrieval using BM25, TF-IDF/LSA, keyword overlap, symbols, and paths.
|
|
67
72
|
- Code dependency graph traversal and graph-augmented context selection.
|
|
68
73
|
- CAG, RAG, hybrid CAG/RAG, long-context, and graph-augmented planning strategies.
|
|
@@ -142,6 +147,12 @@ Install all CTXORA skills from this repository:
|
|
|
142
147
|
npx skills add nguyentrunghieutcu/ctxora-engine
|
|
143
148
|
```
|
|
144
149
|
|
|
150
|
+
Install the curated CTXORA pack:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
npx skills add https://www.skills.sh/p/2fCkKUwjcYsPi0WX
|
|
154
|
+
```
|
|
155
|
+
|
|
145
156
|
List or install one skill:
|
|
146
157
|
|
|
147
158
|
```bash
|
package/README.vi.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
+
<a href="https://ctxora-landing.vercel.app/">
|
|
4
|
+
<img src="assets/ctxora-app-icon.png" alt="Biểu tượng CTXORA" width="128" height="128">
|
|
5
|
+
</a>
|
|
6
|
+
|
|
3
7
|
# CTXORA Engine
|
|
4
8
|
|
|
5
9
|
### Index once. Ground every agent.
|
|
@@ -16,7 +20,7 @@
|
|
|
16
20
|
|
|
17
21
|
[English](README.md) · **Tiếng Việt**
|
|
18
22
|
|
|
19
|
-
[Bắt đầu nhanh](#bắt-đầu-nhanh) · [Cài đặt](#cài-đặt) · [Agent skills](#agent-skills) · [CLI](#tham-chiếu-cli) · [MCP](#mcp-tools) · [Bảo mật](#quyền-riêng-tư-và-bảo-mật)
|
|
23
|
+
[Website](https://ctxora-landing.vercel.app/) · [Bắt đầu nhanh](#bắt-đầu-nhanh) · [Cài đặt](#cài-đặt) · [Agent skills](#agent-skills) · [CLI](#tham-chiếu-cli) · [MCP](#mcp-tools) · [Bảo mật](#quyền-riêng-tư-và-bảo-mật)
|
|
20
24
|
|
|
21
25
|
</div>
|
|
22
26
|
|
|
@@ -63,6 +67,7 @@ Codex · Claude Code · Cursor · Copilot · MCP clients
|
|
|
63
67
|
### Local context engine
|
|
64
68
|
|
|
65
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.
|
|
66
71
|
- Hybrid lexical và local semantic retrieval bằng BM25, TF-IDF/LSA, keyword overlap, symbol và path.
|
|
67
72
|
- Code dependency graph và graph-augmented context selection.
|
|
68
73
|
- Các strategy CAG, RAG, hybrid CAG/RAG, long context và graph augmented.
|
|
@@ -142,6 +147,12 @@ Cài toàn bộ CTXORA skills từ repository này:
|
|
|
142
147
|
npx skills add nguyentrunghieutcu/ctxora-engine
|
|
143
148
|
```
|
|
144
149
|
|
|
150
|
+
Cài pack CTXORA đã được gom sẵn:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
npx skills add https://www.skills.sh/p/2fCkKUwjcYsPi0WX
|
|
154
|
+
```
|
|
155
|
+
|
|
145
156
|
Liệt kê hoặc chỉ cài một skill:
|
|
146
157
|
|
|
147
158
|
```bash
|
|
Binary file
|
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
|
|
|
@@ -36,9 +36,18 @@ function pythonCandidates() {
|
|
|
36
36
|
if (process.env.CTXORA_PYTHON) {
|
|
37
37
|
return [{ command: process.env.CTXORA_PYTHON, prefix: [] }];
|
|
38
38
|
}
|
|
39
|
+
const supportedMinors = ["13", "12", "11", "10"];
|
|
39
40
|
return process.platform === "win32"
|
|
40
|
-
? [
|
|
41
|
-
|
|
41
|
+
? [
|
|
42
|
+
...supportedMinors.map((minor) => ({ command: "py", prefix: [`-3.${minor}`] })),
|
|
43
|
+
{ command: "python", prefix: [] },
|
|
44
|
+
{ command: "python3", prefix: [] },
|
|
45
|
+
]
|
|
46
|
+
: [
|
|
47
|
+
...supportedMinors.map((minor) => ({ command: `python3.${minor}`, prefix: [] })),
|
|
48
|
+
{ command: "python3", prefix: [] },
|
|
49
|
+
{ command: "python", prefix: [] },
|
|
50
|
+
];
|
|
42
51
|
}
|
|
43
52
|
|
|
44
53
|
export function findPython() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ctxora",
|
|
3
|
-
"version": "6.2.
|
|
3
|
+
"version": "6.2.2",
|
|
4
4
|
"description": "Local-first context engine for coding agents.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"bin",
|
|
11
11
|
"src/**/*.py",
|
|
12
12
|
"pyproject.toml",
|
|
13
|
+
"assets/ctxora-app-icon.png",
|
|
13
14
|
"README.md",
|
|
14
15
|
"README.vi.md",
|
|
15
16
|
"LICENSE"
|
|
@@ -34,7 +35,7 @@
|
|
|
34
35
|
"type": "git",
|
|
35
36
|
"url": "git+https://github.com/nguyentrunghieutcu/ctxora-engine.git"
|
|
36
37
|
},
|
|
37
|
-
"homepage": "https://
|
|
38
|
+
"homepage": "https://ctxora-landing.vercel.app/",
|
|
38
39
|
"bugs": {
|
|
39
40
|
"url": "https://github.com/nguyentrunghieutcu/ctxora-engine/issues"
|
|
40
41
|
},
|
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")
|