ctxora 6.3.0 → 6.4.0
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/.claude-plugin/plugin.json +1 -1
- package/README.md +3 -1
- package/README.vi.md +4 -1
- package/bin/ctxora.mjs +1 -1
- package/commands/route.md +1 -1
- package/package.json +1 -1
- package/pyproject.toml +1 -1
- package/skills/ctxora-continuous-learning/SKILL.md +1 -1
- package/src/harness_context/application/context_service.py +1 -1
- package/src/harness_context/cli/app.py +24 -6
- package/src/harness_context/skills/catalog.py +22 -0
- package/src/harness_context/skills/router.py +6 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ctxora",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.4.0",
|
|
4
4
|
"description": "CTXORA repository context, memory, handoff, and diagnostics workflows.",
|
|
5
5
|
"homepage": "https://ctxora-landing.vercel.app/",
|
|
6
6
|
"repository": "https://github.com/nguyentrunghieutcu/ctxora-engine",
|
package/README.md
CHANGED
|
@@ -180,10 +180,12 @@ npx ctxora skills preview --workspace . --profile developer \
|
|
|
180
180
|
--add-module security --remove-skill security-scan
|
|
181
181
|
npx ctxora skills install --workspace . --profile developer \
|
|
182
182
|
--add-module security --remove-skill security-scan
|
|
183
|
+
ctxora skills install --workspace . --profile developer \
|
|
184
|
+
--target codex --target claude --target cursor --target gemini
|
|
183
185
|
ctxora skills route "Fix React hydration performance" --workspace . --profile developer
|
|
184
186
|
```
|
|
185
187
|
|
|
186
|
-
The default
|
|
188
|
+
The default target is Codex-compatible `.agents/skills`. Use repeatable `--target codex|claude|cursor|gemini|opencode`, `--target all`, or `--output` for a custom directory. Preview never mutates files. Install refuses to overwrite modified skills unless `--force` is explicit, and `--prune` removes only unchanged skills previously installed by CTXORA. See `THIRD_PARTY_NOTICES.md` for provenance and licensing.
|
|
187
189
|
|
|
188
190
|
### Commands and agent roles
|
|
189
191
|
|
package/README.vi.md
CHANGED
|
@@ -180,9 +180,11 @@ npx ctxora skills preview --workspace . --profile developer \
|
|
|
180
180
|
--add-module security --remove-skill security-scan
|
|
181
181
|
npx ctxora skills install --workspace . --profile developer \
|
|
182
182
|
--add-module security --remove-skill security-scan
|
|
183
|
+
ctxora skills install --workspace . --profile developer \
|
|
184
|
+
--target codex --target claude --target cursor --target gemini
|
|
183
185
|
```
|
|
184
186
|
|
|
185
|
-
|
|
187
|
+
Target mặc định là `.agents/skills` tương thích Codex. Có thể lặp `--target codex|claude|cursor|gemini|opencode`, dùng `--target all`, hoặc `--output` cho thư mục tùy chỉnh. Preview không sửa file. Install không ghi đè skill đã chỉnh sửa nếu chưa truyền `--force`; `--prune` chỉ xóa skill chưa bị sửa và trước đó do CTXORA cài. Xem provenance và license tại `THIRD_PARTY_NOTICES.md`.
|
|
186
188
|
|
|
187
189
|
### Command và agent role
|
|
188
190
|
|
|
@@ -193,6 +195,7 @@ CTXORA cũng cung cấp các template workflow chủ động, lấy cảm hứng
|
|
|
193
195
|
| Command | Mục đích | Khả năng CTXORA |
|
|
194
196
|
|---|---|---|
|
|
195
197
|
| `/ctxora:context <task>` | Lấy bằng chứng repository trước khi code | `plan_context`, `retrieve_context`, `prepare_context` |
|
|
198
|
+
| `/ctxora:route <task>` | Tự chọn skill trong profile và học sau validation | `route_skills`, `skill_feedback` |
|
|
196
199
|
| `/ctxora:plan <task>` | Lập kế hoạch dựa trên context | `plan_context`, `retrieve_context` |
|
|
197
200
|
| `/ctxora:review [scope]` | Review thay đổi với context repository | `retrieve_context` |
|
|
198
201
|
| `/ctxora:health` | Kiểm tra workspace và index | `doctor`, `context-score`, `inspect` |
|
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.
|
|
9
|
+
const PACKAGE_VERSION = "6.4.0";
|
|
10
10
|
const PYTHON_RANGE = "3.10-3.13";
|
|
11
11
|
const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
12
12
|
|
package/commands/route.md
CHANGED
|
@@ -3,4 +3,4 @@ description: Automatically rank the installed ECC skills for a task.
|
|
|
3
3
|
argument-hint: <task>
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
Call `route_skills` for the registered workspace and `$ARGUMENTS`. Use the highest-ranked relevant recommendations, read their `SKILL.md` files before acting, and retain the returned `route_id
|
|
6
|
+
Call `route_skills` for the registered workspace and `$ARGUMENTS`. Use the highest-ranked relevant recommendations, read their `SKILL.md` files before acting, and retain the returned `route_id` in task state. After validation passes, automatically call `skill_feedback` with outcome `success` and the skills actually used. Use `failure` only when the failed result is attributable to the guidance; if the user replaces the selected skill, use `corrected`. Do not ask the user to submit routine feedback manually, and do not execute bundled scripts or external actions merely because a routed skill mentions them.
|
package/package.json
CHANGED
package/pyproject.toml
CHANGED
|
@@ -7,7 +7,7 @@ description: Capture evidence-backed project lessons in CTXORA memory and promot
|
|
|
7
7
|
|
|
8
8
|
CTXORA learning is deliberate and memory-based; it does not require background hooks.
|
|
9
9
|
|
|
10
|
-
Skill-routing learning is separate from durable memory. Keep the `route_id` returned by `route_skills` or `prepare_context
|
|
10
|
+
Skill-routing learning is separate from durable memory. Keep the `route_id` returned by `route_skills` or `prepare_context` in task state. After validation passes, automatically call `skill_feedback` with `success` and the skills actually used; use `failure` only when the failed result is attributable to the guidance, and `corrected` when the user replaces the routed skill. Do not ask the user to submit routine feedback manually. CTXORA stores only a task fingerprint, matched catalog terms, bounded counters, and decayed associations; it never stores raw tasks or transcripts.
|
|
11
11
|
|
|
12
12
|
Inspect connected tool schemas and resolve the registered workspace ID before using `memory_search` or `memory_save`. If tools are unavailable, present a proposed lesson and explicitly report that it was not saved. Do not write directly into memory databases or ECC vaults. Do not capture raw session transcripts or install observers as part of this skill.
|
|
13
13
|
|
|
@@ -47,7 +47,7 @@ class ContextService:
|
|
|
47
47
|
if self.skill_router is not None:
|
|
48
48
|
try:
|
|
49
49
|
routed = self.skill_router.route(request.workspace_id, request.query, top_k=3, include_instructions=False, token_budget=0)
|
|
50
|
-
skill_diagnostics.update({"route_id": routed["route_id"], "profile": routed["profile"], "recommendations": routed["recommendations"]})
|
|
50
|
+
skill_diagnostics.update({"route_id": routed["route_id"], "profile": routed["profile"], "recommendations": routed["recommendations"], "feedback_policy": routed["feedback_policy"]})
|
|
51
51
|
except ValueError as error:
|
|
52
52
|
skill_diagnostics.update({"recommendations": [], "routing_error": str(error)})
|
|
53
53
|
elapsed_ms = (time.perf_counter() - started) * 1000
|
|
@@ -119,7 +119,13 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
119
119
|
action_parser.add_argument("--remove-module", action="append", default=[])
|
|
120
120
|
action_parser.add_argument("--add-skill", action="append", default=[])
|
|
121
121
|
action_parser.add_argument("--remove-skill", action="append", default=[])
|
|
122
|
-
action_parser.add_argument("--output", default="
|
|
122
|
+
action_parser.add_argument("--output", default="")
|
|
123
|
+
action_parser.add_argument(
|
|
124
|
+
"--target",
|
|
125
|
+
action="append",
|
|
126
|
+
choices=("codex", "claude", "cursor", "gemini", "opencode", "all"),
|
|
127
|
+
default=[],
|
|
128
|
+
)
|
|
123
129
|
action_parser.add_argument("--force", action="store_true")
|
|
124
130
|
action_parser.add_argument("--prune", action="store_true")
|
|
125
131
|
if action == "install":
|
|
@@ -191,13 +197,25 @@ def _main(argv: list[str] | None = None) -> int:
|
|
|
191
197
|
tuple(args.remove_skill),
|
|
192
198
|
)
|
|
193
199
|
dry_run = args.skills_action == "preview" or args.dry_run
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
200
|
+
installs = []
|
|
201
|
+
conflicts = []
|
|
202
|
+
for target, output in catalog.install_outputs(tuple(args.target), args.output):
|
|
203
|
+
installed = catalog.install(
|
|
204
|
+
root, output, selection, force=args.force, prune=args.prune, dry_run=dry_run
|
|
205
|
+
)
|
|
206
|
+
installed["target"] = target
|
|
207
|
+
installs.append(installed)
|
|
208
|
+
conflicts.extend(f"{target}:{skill}" for skill in installed["conflicts"])
|
|
209
|
+
result = {
|
|
210
|
+
"status": "conflict" if conflicts else ("planned" if dry_run else "installed"),
|
|
211
|
+
"selection": selection.to_dict(),
|
|
212
|
+
"installs": installs,
|
|
213
|
+
"conflicts": conflicts,
|
|
214
|
+
}
|
|
215
|
+
if not dry_run and not conflicts:
|
|
198
216
|
result["profile_config"] = str(catalog.write_selection(root, selection))
|
|
199
217
|
_print(result)
|
|
200
|
-
return 2 if
|
|
218
|
+
return 2 if conflicts else 0
|
|
201
219
|
if args.command == "setup":
|
|
202
220
|
config = workspace_data_dir(root) / "config.toml"
|
|
203
221
|
config.parent.mkdir(parents=True, exist_ok=True)
|
|
@@ -9,6 +9,14 @@ from dataclasses import dataclass
|
|
|
9
9
|
from pathlib import Path
|
|
10
10
|
from typing import Any
|
|
11
11
|
|
|
12
|
+
SKILL_INSTALL_TARGETS = {
|
|
13
|
+
"codex": ".agents/skills",
|
|
14
|
+
"claude": ".claude/skills",
|
|
15
|
+
"cursor": ".cursor/skills",
|
|
16
|
+
"gemini": ".gemini/skills",
|
|
17
|
+
"opencode": ".opencode/skills",
|
|
18
|
+
}
|
|
19
|
+
|
|
12
20
|
|
|
13
21
|
@dataclass(frozen=True)
|
|
14
22
|
class SkillSelection:
|
|
@@ -95,6 +103,20 @@ class SkillCatalog:
|
|
|
95
103
|
def source_root(self) -> Path:
|
|
96
104
|
return Path(__file__).with_name("ecc")
|
|
97
105
|
|
|
106
|
+
@staticmethod
|
|
107
|
+
def install_outputs(targets: tuple[str, ...], output: str = "") -> tuple[tuple[str, str], ...]:
|
|
108
|
+
if output and targets:
|
|
109
|
+
raise ValueError("use either --output or --target, not both")
|
|
110
|
+
if output:
|
|
111
|
+
return (("custom", output),)
|
|
112
|
+
selected = list(targets or ("codex",))
|
|
113
|
+
if "all" in selected:
|
|
114
|
+
selected = list(SKILL_INSTALL_TARGETS)
|
|
115
|
+
unknown = sorted(set(selected) - set(SKILL_INSTALL_TARGETS))
|
|
116
|
+
if unknown:
|
|
117
|
+
raise ValueError(f"unknown skill install target: {unknown[0]}")
|
|
118
|
+
return tuple((name, SKILL_INSTALL_TARGETS[name]) for name in dict.fromkeys(selected))
|
|
119
|
+
|
|
98
120
|
def install(
|
|
99
121
|
self,
|
|
100
122
|
workspace: str | Path,
|
|
@@ -165,6 +165,12 @@ class SkillRouter:
|
|
|
165
165
|
"candidate_count": len(candidates),
|
|
166
166
|
"recommendations": recommendations,
|
|
167
167
|
"learning": {"project_scoped": True, "raw_tasks_stored": False},
|
|
168
|
+
"feedback_policy": {
|
|
169
|
+
"mode": "after_validation",
|
|
170
|
+
"retain_route_id": True,
|
|
171
|
+
"success_requires_validation": True,
|
|
172
|
+
"user_correction_outcome": "corrected",
|
|
173
|
+
},
|
|
168
174
|
}
|
|
169
175
|
|
|
170
176
|
def feedback(
|