code-search-cli 0.1.0__py3-none-any.whl
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.
- code_retrieval/__init__.py +6 -0
- code_retrieval/__main__.py +3 -0
- code_retrieval/cli.py +144 -0
- code_retrieval/engine.py +722 -0
- code_retrieval/index_store.py +286 -0
- code_retrieval/installer.py +65 -0
- code_retrieval/models.py +90 -0
- code_retrieval/query.py +61 -0
- code_retrieval/repository.py +161 -0
- code_retrieval/resources/code-search/SKILL.md +47 -0
- code_retrieval/resources/code-search/agents/openai.yaml +4 -0
- code_retrieval/structure.py +115 -0
- code_search_cli-0.1.0.dist-info/METADATA +287 -0
- code_search_cli-0.1.0.dist-info/RECORD +19 -0
- code_search_cli-0.1.0.dist-info/WHEEL +5 -0
- code_search_cli-0.1.0.dist-info/entry_points.txt +2 -0
- code_search_cli-0.1.0.dist-info/licenses/LICENSE +202 -0
- code_search_cli-0.1.0.dist-info/licenses/NOTICE +7 -0
- code_search_cli-0.1.0.dist-info/top_level.txt +1 -0
code_retrieval/cli.py
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import json
|
|
5
|
+
import sqlite3
|
|
6
|
+
import subprocess
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
from .engine import RetrievalEngine
|
|
10
|
+
from .index_store import PersistentIndex
|
|
11
|
+
from .installer import install_codex_skill, uninstall_codex_skill
|
|
12
|
+
from .models import Evidence
|
|
13
|
+
from .repository import RepositoryReader
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def build_parser() -> argparse.ArgumentParser:
|
|
17
|
+
parser = argparse.ArgumentParser(prog="code-search", description="Task-aware local code retrieval")
|
|
18
|
+
subparsers = parser.add_subparsers(dest="command", required=True)
|
|
19
|
+
|
|
20
|
+
retrieve = subparsers.add_parser("retrieve", help="build an evidence bundle for a task")
|
|
21
|
+
_repository_args(retrieve)
|
|
22
|
+
retrieve.add_argument("--task", required=True, help="engineering task or failure description")
|
|
23
|
+
retrieve.add_argument("--max-evidence", type=int, default=16)
|
|
24
|
+
retrieve.add_argument("--format", choices=("markdown", "json"), default="markdown")
|
|
25
|
+
|
|
26
|
+
expand = subparsers.add_parser("expand", help="expand a known source anchor")
|
|
27
|
+
_repository_args(expand)
|
|
28
|
+
expand.add_argument("--path", required=True, help="repository-relative source path")
|
|
29
|
+
anchor = expand.add_mutually_exclusive_group()
|
|
30
|
+
anchor.add_argument("--line", type=int)
|
|
31
|
+
anchor.add_argument("--symbol")
|
|
32
|
+
expand.add_argument("--relation", choices=("enclosing", "siblings", "references"), default="enclosing")
|
|
33
|
+
expand.add_argument("--format", choices=("markdown", "json"), default="markdown")
|
|
34
|
+
|
|
35
|
+
index = subparsers.add_parser("index", help="build or incrementally refresh the persistent index")
|
|
36
|
+
_repository_args(index)
|
|
37
|
+
index.add_argument("--format", choices=("text", "json"), default="text")
|
|
38
|
+
|
|
39
|
+
status = subparsers.add_parser("status", help="show persistent index freshness")
|
|
40
|
+
_repository_args(status)
|
|
41
|
+
status.add_argument("--format", choices=("text", "json"), default="text")
|
|
42
|
+
|
|
43
|
+
clean = subparsers.add_parser("clean", help="remove the persistent index for a repository")
|
|
44
|
+
_repository_args(clean)
|
|
45
|
+
|
|
46
|
+
install = subparsers.add_parser("install", help="install the bundled Codex skill")
|
|
47
|
+
install.add_argument("--force", action="store_true", help="replace a locally modified installed skill")
|
|
48
|
+
|
|
49
|
+
uninstall = subparsers.add_parser("uninstall", help="remove the bundled Codex skill")
|
|
50
|
+
uninstall.add_argument("--force", action="store_true", help="remove a locally modified installed skill")
|
|
51
|
+
return parser
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def main(argv: list[str] | None = None) -> int:
|
|
55
|
+
args = build_parser().parse_args(argv)
|
|
56
|
+
try:
|
|
57
|
+
if args.command in {"install", "uninstall"}:
|
|
58
|
+
operation = install_codex_skill if args.command == "install" else uninstall_codex_skill
|
|
59
|
+
path, action = operation(force=args.force)
|
|
60
|
+
print(f"Codex skill {action}: {path}")
|
|
61
|
+
if args.command == "install":
|
|
62
|
+
print("Restart Codex to load the skill.")
|
|
63
|
+
return 0
|
|
64
|
+
|
|
65
|
+
if args.command in {"index", "status", "clean"}:
|
|
66
|
+
store = PersistentIndex(RepositoryReader(args.repo, args.ref))
|
|
67
|
+
if args.command == "clean":
|
|
68
|
+
removed = store.clean()
|
|
69
|
+
print(f"Index {'removed' if removed else 'not found'}: {store.path}")
|
|
70
|
+
return 0
|
|
71
|
+
report = store.refresh() if args.command == "index" else store.status()
|
|
72
|
+
data = report.to_dict()
|
|
73
|
+
if args.format == "json":
|
|
74
|
+
print(json.dumps(data, ensure_ascii=False, indent=2))
|
|
75
|
+
else:
|
|
76
|
+
print(_index_text(args.command, data))
|
|
77
|
+
return 0
|
|
78
|
+
|
|
79
|
+
engine = RetrievalEngine(args.repo, args.ref)
|
|
80
|
+
if args.command == "retrieve":
|
|
81
|
+
result = engine.retrieve(args.task, args.max_evidence)
|
|
82
|
+
output = json.dumps(result.to_dict(), ensure_ascii=False, indent=2) if args.format == "json" else result.to_markdown()
|
|
83
|
+
else:
|
|
84
|
+
evidence = engine.expand(
|
|
85
|
+
args.path,
|
|
86
|
+
line=args.line,
|
|
87
|
+
symbol=args.symbol,
|
|
88
|
+
relation=args.relation,
|
|
89
|
+
)
|
|
90
|
+
output = _evidence_json(evidence) if args.format == "json" else _evidence_markdown(evidence)
|
|
91
|
+
print(output)
|
|
92
|
+
return 0
|
|
93
|
+
except (OSError, ValueError, sqlite3.Error, subprocess.SubprocessError) as error:
|
|
94
|
+
print(f"error: {error}", file=sys.stderr)
|
|
95
|
+
return 2
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _repository_args(parser: argparse.ArgumentParser) -> None:
|
|
99
|
+
parser.add_argument("--repo", required=True, help="local repository path")
|
|
100
|
+
parser.add_argument("--ref", help="optional Git commit, tag, or branch; does not modify the working tree")
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _evidence_json(evidence: list[Evidence]) -> str:
|
|
104
|
+
from dataclasses import asdict
|
|
105
|
+
|
|
106
|
+
return json.dumps([asdict(item) for item in evidence], ensure_ascii=False, indent=2)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _evidence_markdown(evidence: list[Evidence]) -> str:
|
|
110
|
+
lines = ["# Expanded evidence", ""]
|
|
111
|
+
for item in evidence:
|
|
112
|
+
lines.extend(
|
|
113
|
+
[
|
|
114
|
+
f"## `{item.path}:{item.start_line}-{item.end_line}`",
|
|
115
|
+
"",
|
|
116
|
+
"; ".join(item.reasons),
|
|
117
|
+
"",
|
|
118
|
+
"```",
|
|
119
|
+
item.content.rstrip(),
|
|
120
|
+
"```",
|
|
121
|
+
"",
|
|
122
|
+
]
|
|
123
|
+
)
|
|
124
|
+
return "\n".join(lines)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def _index_text(command: str, data: dict[str, object]) -> str:
|
|
128
|
+
if command == "status":
|
|
129
|
+
state = "fresh" if data["fresh"] else ("stale" if data["exists"] else "not built")
|
|
130
|
+
return (
|
|
131
|
+
f"Index {state}: {data['index_path']}\n"
|
|
132
|
+
f"Source files: {data['source_files']}; pending +{data['added']} "
|
|
133
|
+
f"~{data['updated']} -{data['removed']}"
|
|
134
|
+
)
|
|
135
|
+
return (
|
|
136
|
+
f"Index refreshed: {data['index_path']}\n"
|
|
137
|
+
f"Source files: {data['source_files']}; +{data['added']} "
|
|
138
|
+
f"~{data['updated']} -{data['removed']}; unchanged {data['unchanged']}; "
|
|
139
|
+
f"{data['elapsed_ms']} ms"
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
if __name__ == "__main__":
|
|
144
|
+
raise SystemExit(main())
|