@pmaddire/gcie 0.1.4 → 0.1.6
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/AGENT.md +6 -2
- package/GCIE_USAGE.md +212 -153
- package/README.md +30 -8
- package/bench_questions.py +69 -0
- package/cli/app.py +198 -162
- package/cli/commands/adaptation.py +352 -0
- package/cli/commands/context.py +682 -34
- package/cli/commands/context_slices.py +1322 -601
- package/cli/commands/setup.py +86 -72
- package/context/architecture_slicer.py +2 -1
- package/llm_context/snippet_selector.py +1 -1
- package/package.json +1 -1
- package/retrieval/hybrid_retriever.py +9 -1
package/cli/app.py
CHANGED
|
@@ -1,163 +1,199 @@
|
|
|
1
|
-
"""Typer entrypoint for GCIE CLI."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import json
|
|
6
|
-
import re
|
|
7
|
-
|
|
8
|
-
import typer
|
|
9
|
-
|
|
10
|
-
from .commands.
|
|
11
|
-
from .commands.
|
|
12
|
-
from .commands.
|
|
13
|
-
from .commands.
|
|
14
|
-
from .commands.
|
|
15
|
-
from .commands.
|
|
16
|
-
from .commands.
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
budget_val =
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
typer.
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
1
|
+
"""Typer entrypoint for GCIE CLI."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import re
|
|
7
|
+
|
|
8
|
+
import typer
|
|
9
|
+
|
|
10
|
+
from .commands.adaptation import run_post_init_adaptation
|
|
11
|
+
from .commands.cache import cache_status, clear_cache, warm_cache
|
|
12
|
+
from .commands.context import run_context, run_context_basic
|
|
13
|
+
from .commands.context_slices import adaptive_profile_summary, clear_adaptive_profile, run_context_slices
|
|
14
|
+
from .commands.debug import run_debug
|
|
15
|
+
from .commands.index import run_index
|
|
16
|
+
from .commands.query import run_query
|
|
17
|
+
from .commands.setup import run_setup
|
|
18
|
+
|
|
19
|
+
app = typer.Typer(help="GraphCode Intelligence Engine CLI")
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _query_tokens(query: str) -> tuple[str, ...]:
|
|
23
|
+
return tuple(re.findall(r"[a-zA-Z_./{}-][a-zA-Z0-9_./{}-]*", query.lower()))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _auto_context_budget(query: str, intent: str | None) -> int | None:
|
|
27
|
+
tokens = _query_tokens(query)
|
|
28
|
+
lowered = query.lower()
|
|
29
|
+
effective_intent = intent or "explore"
|
|
30
|
+
|
|
31
|
+
file_terms = [token for token in tokens if "." in token or "/" in token or "{" in token]
|
|
32
|
+
explicit_files = [token for token in file_terms if token.endswith((".py", ".jsx", ".js", ".tsx", ".ts", ".html"))]
|
|
33
|
+
symbol_terms = [token for token in tokens if any(ch in token for ch in ("_", "/", ".", "{", "}"))]
|
|
34
|
+
|
|
35
|
+
has_frontend = any(token.startswith(("frontend/", "frontend\\")) for token in file_terms)
|
|
36
|
+
has_backend = any(
|
|
37
|
+
token.endswith(".py") or token.startswith(("backend/", "server/", "api/"))
|
|
38
|
+
for token in file_terms
|
|
39
|
+
)
|
|
40
|
+
cross_layer = has_frontend and has_backend
|
|
41
|
+
|
|
42
|
+
stage_pipeline = any(term in lowered for term in ("stage", "pipeline", "planner", "plan", "build", "orchestr"))
|
|
43
|
+
backend_config = any(term in lowered for term in ("backend", "config", "openai", "api_key", "llm", "no_ai", "backend_info"))
|
|
44
|
+
ai_chain = any(term in lowered for term in ("openai", "llm", "model", "agent")) and has_backend
|
|
45
|
+
same_layer_backend_pair = len([token for token in explicit_files if token.endswith(".py")]) >= 2 and not has_frontend
|
|
46
|
+
has_api = "/api/" in lowered or any("/api/" in token for token in file_terms)
|
|
47
|
+
|
|
48
|
+
if effective_intent in {"edit", "debug", "refactor"} and cross_layer and len(symbol_terms) >= 4:
|
|
49
|
+
return 1200 if has_api else 1150
|
|
50
|
+
if stage_pipeline and len(explicit_files) >= 2:
|
|
51
|
+
return 1400
|
|
52
|
+
if same_layer_backend_pair and (backend_config or ai_chain):
|
|
53
|
+
return 1100
|
|
54
|
+
if len(explicit_files) >= 3 and effective_intent in {"edit", "debug", "refactor"}:
|
|
55
|
+
return 1200
|
|
56
|
+
if effective_intent in {"edit", "debug"} and len(explicit_files) >= 2:
|
|
57
|
+
return 1000
|
|
58
|
+
if effective_intent == "refactor" and len(explicit_files) >= 2:
|
|
59
|
+
return 1000
|
|
60
|
+
return None
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@app.command("index")
|
|
64
|
+
def index_cmd(path: str = typer.Argument(".")) -> None:
|
|
65
|
+
result = run_index(path)
|
|
66
|
+
typer.echo(json.dumps(result, indent=2))
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
@app.command("query")
|
|
70
|
+
def query_cmd(path: str, query: str, max_hops: int = 2) -> None:
|
|
71
|
+
result = run_query(path, query, max_hops=max_hops)
|
|
72
|
+
typer.echo(json.dumps(result, indent=2))
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@app.command("debug")
|
|
76
|
+
def debug_cmd(path: str, query: str) -> None:
|
|
77
|
+
result = run_debug(path, query)
|
|
78
|
+
typer.echo(json.dumps(result, indent=2))
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@app.command("context")
|
|
82
|
+
def context_cmd(
|
|
83
|
+
path: str,
|
|
84
|
+
query: str,
|
|
85
|
+
budget: str = typer.Option("auto", "--budget"),
|
|
86
|
+
intent: str | None = typer.Option(None, "--intent"),
|
|
87
|
+
mode: str = typer.Option("basic", "--mode", help="context mode: basic or adaptive"),
|
|
88
|
+
) -> None:
|
|
89
|
+
if budget == "auto":
|
|
90
|
+
budget_val = _auto_context_budget(query, intent)
|
|
91
|
+
else:
|
|
92
|
+
budget_val = int(budget)
|
|
93
|
+
|
|
94
|
+
if mode == "basic":
|
|
95
|
+
result = run_context_basic(path, query, budget=budget_val, intent=intent)
|
|
96
|
+
elif mode == "adaptive":
|
|
97
|
+
result = run_context(path, query, budget=budget_val, intent=intent)
|
|
98
|
+
else:
|
|
99
|
+
raise typer.BadParameter("--mode must be 'basic' or 'adaptive'")
|
|
100
|
+
typer.echo(json.dumps(result, indent=2))
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@app.command("context-slices")
|
|
104
|
+
def context_slices_cmd(
|
|
105
|
+
repo: str,
|
|
106
|
+
query: str,
|
|
107
|
+
profile: str | None = typer.Option("recall", "--profile"),
|
|
108
|
+
stage_a_budget: int = typer.Option(400, "--stage-a"),
|
|
109
|
+
stage_b_budget: int = typer.Option(800, "--stage-b"),
|
|
110
|
+
max_total: int = typer.Option(1200, "--max-total"),
|
|
111
|
+
intent: str | None = typer.Option(None, "--intent"),
|
|
112
|
+
pin: str | None = typer.Option(None, "--pin"),
|
|
113
|
+
pin_budget: int = typer.Option(300, "--pin-budget"),
|
|
114
|
+
include_tests: bool = typer.Option(False, "--include-tests"),
|
|
115
|
+
) -> None:
|
|
116
|
+
result = run_context_slices(
|
|
117
|
+
repo,
|
|
118
|
+
query,
|
|
119
|
+
stage_a_budget=stage_a_budget,
|
|
120
|
+
stage_b_budget=stage_b_budget,
|
|
121
|
+
max_total=max_total,
|
|
122
|
+
intent=intent,
|
|
123
|
+
pin=pin,
|
|
124
|
+
pin_budget=pin_budget,
|
|
125
|
+
include_tests=include_tests,
|
|
126
|
+
profile=profile,
|
|
127
|
+
)
|
|
128
|
+
typer.echo(json.dumps(result, indent=2))
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
@app.command("adaptive-profile")
|
|
132
|
+
def adaptive_profile_cmd(
|
|
133
|
+
repo: str = typer.Argument("."),
|
|
134
|
+
clear: bool = typer.Option(False, "--clear", help="Clear learned adaptive profile"),
|
|
135
|
+
) -> None:
|
|
136
|
+
result = clear_adaptive_profile(repo) if clear else adaptive_profile_summary(repo)
|
|
137
|
+
typer.echo(json.dumps(result, indent=2))
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
@app.command("adapt")
|
|
141
|
+
def adapt_cmd(
|
|
142
|
+
repo: str = typer.Argument("."),
|
|
143
|
+
benchmark_size: int = typer.Option(10, "--benchmark-size"),
|
|
144
|
+
efficiency_iterations: int = typer.Option(5, "--efficiency-iterations"),
|
|
145
|
+
clear_profile: bool = typer.Option(False, "--clear-profile"),
|
|
146
|
+
) -> None:
|
|
147
|
+
result = run_post_init_adaptation(
|
|
148
|
+
repo,
|
|
149
|
+
benchmark_size=benchmark_size,
|
|
150
|
+
efficiency_iterations=efficiency_iterations,
|
|
151
|
+
clear_profile=clear_profile,
|
|
152
|
+
)
|
|
153
|
+
typer.echo(json.dumps(result, indent=2))
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
@app.command("setup")
|
|
157
|
+
def setup_cmd(
|
|
158
|
+
path: str = typer.Argument("."),
|
|
159
|
+
force: bool = typer.Option(False, "--force", help="Overwrite existing setup files"),
|
|
160
|
+
no_agent_usage: bool = typer.Option(False, "--no-agent-usage", help="Do not copy GCIE_USAGE.md"),
|
|
161
|
+
no_setup_doc: bool = typer.Option(False, "--no-setup-doc", help="Do not copy SETUP_ANY_REPO.md"),
|
|
162
|
+
no_index: bool = typer.Option(False, "--no-index", help="Skip initial indexing pass"),
|
|
163
|
+
adapt: bool = typer.Option(False, "--adapt", help="Run post-init adaptation pipeline after setup"),
|
|
164
|
+
adaptation_benchmark_size: int = typer.Option(10, "--adapt-benchmark-size"),
|
|
165
|
+
adaptation_efficiency_iterations: int = typer.Option(5, "--adapt-efficiency-iterations"),
|
|
166
|
+
) -> None:
|
|
167
|
+
result = run_setup(
|
|
168
|
+
path,
|
|
169
|
+
force=force,
|
|
170
|
+
include_agent_usage=not no_agent_usage,
|
|
171
|
+
include_setup_doc=not no_setup_doc,
|
|
172
|
+
run_index_pass=not no_index,
|
|
173
|
+
run_adaptation_pass=adapt,
|
|
174
|
+
adaptation_benchmark_size=adaptation_benchmark_size,
|
|
175
|
+
adaptation_efficiency_iterations=adaptation_efficiency_iterations,
|
|
176
|
+
)
|
|
177
|
+
typer.echo(json.dumps(result, indent=2))
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
@app.command("cache-clear")
|
|
181
|
+
def cache_clear_cmd(path: str = typer.Argument(".")) -> None:
|
|
182
|
+
result = clear_cache(path)
|
|
183
|
+
typer.echo(json.dumps(result, indent=2))
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
@app.command("cache-status")
|
|
187
|
+
def cache_status_cmd(path: str = typer.Argument(".")) -> None:
|
|
188
|
+
result = cache_status(path)
|
|
189
|
+
typer.echo(json.dumps(result, indent=2))
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
@app.command("cache-warm")
|
|
193
|
+
def cache_warm_cmd(path: str = typer.Argument(".")) -> None:
|
|
194
|
+
result = warm_cache(path)
|
|
195
|
+
typer.echo(json.dumps(result, indent=2))
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
if __name__ == "__main__":
|
|
162
199
|
app()
|
|
163
|
-
|