localcode 0.3.7__py3-none-any.whl → 0.3.9__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.
- localcode/__init__.py +1 -1
- localcode/agent/loop.py +33 -13
- localcode/tools/project_check.py +118 -0
- localcode/tools/syntax_check.py +78 -89
- {localcode-0.3.7.dist-info → localcode-0.3.9.dist-info}/METADATA +3 -1
- {localcode-0.3.7.dist-info → localcode-0.3.9.dist-info}/RECORD +10 -9
- {localcode-0.3.7.dist-info → localcode-0.3.9.dist-info}/WHEEL +0 -0
- {localcode-0.3.7.dist-info → localcode-0.3.9.dist-info}/entry_points.txt +0 -0
- {localcode-0.3.7.dist-info → localcode-0.3.9.dist-info}/licenses/LICENSE +0 -0
- {localcode-0.3.7.dist-info → localcode-0.3.9.dist-info}/top_level.txt +0 -0
localcode/__init__.py
CHANGED
localcode/agent/loop.py
CHANGED
|
@@ -1240,24 +1240,44 @@ def run_agent_loop(
|
|
|
1240
1240
|
and not ran_build_or_test(bash_history)
|
|
1241
1241
|
):
|
|
1242
1242
|
_build_verify_nudges += 1
|
|
1243
|
+
# TIER-2 VERIFICATION: don't just NUDGE the model to typecheck
|
|
1244
|
+
# (a small model skips it or mishandles output) — RUN the
|
|
1245
|
+
# project's real typecheck/lint ourselves and feed the concrete
|
|
1246
|
+
# errors back. Catches semantic errors (wrong names, missing
|
|
1247
|
+
# imports) the per-write syntax check can't. Light: once per
|
|
1248
|
+
# turn, at completion. See tools.project_check.
|
|
1249
|
+
_proj_errors = None
|
|
1250
|
+
try:
|
|
1251
|
+
from ..tools.project_check import run_project_check
|
|
1252
|
+
out.print_info("Verifying — running the project's typecheck…")
|
|
1253
|
+
_proj_errors = run_project_check(str(app.repo_root))
|
|
1254
|
+
except Exception:
|
|
1255
|
+
_proj_errors = None
|
|
1243
1256
|
try:
|
|
1244
1257
|
from ..events import emit as _emit_bg
|
|
1245
|
-
_emit_bg("auto_nudge", signal="build_unverified",
|
|
1258
|
+
_emit_bg("auto_nudge", signal="build_unverified",
|
|
1259
|
+
round_idx=round_num, had_errors=bool(_proj_errors))
|
|
1246
1260
|
except Exception:
|
|
1247
1261
|
pass
|
|
1248
|
-
|
|
1249
|
-
"
|
|
1250
|
-
"
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1262
|
+
if _proj_errors:
|
|
1263
|
+
out.print_info("Typecheck found errors — sending them back to fix.")
|
|
1264
|
+
messages.append({"role": "user", "content": (
|
|
1265
|
+
"SYSTEM: the project's typecheck/build was run for you and "
|
|
1266
|
+
"reported errors. FIX each one (targeted edit_file changes), "
|
|
1267
|
+
"then finish. Do not claim it works until these are gone:\n\n"
|
|
1268
|
+
+ _proj_errors
|
|
1269
|
+
)})
|
|
1270
|
+
else:
|
|
1271
|
+
# No checker available, or it passed — fall back to advising.
|
|
1272
|
+
out.print_info("Changed code but never built/ran it — nudging to verify.")
|
|
1273
|
+
messages.append({"role": "user", "content": (
|
|
1274
|
+
"SYSTEM: You changed code but never built, type-checked, or ran "
|
|
1275
|
+
"it. Run the project's build/typecheck (npm run build / npx tsc "
|
|
1276
|
+
"--noEmit for TS; tests or an import smoke-check for Python), fix "
|
|
1277
|
+
"every error, then finish. Don't claim it works without building."
|
|
1278
|
+
)})
|
|
1259
1279
|
_ephemeral_nudge_indices.append(len(messages) - 1)
|
|
1260
|
-
continue # don't accept completion — let it
|
|
1280
|
+
continue # don't accept completion — let it fix first
|
|
1261
1281
|
if _goal_state.goal_type == "run_or_launch":
|
|
1262
1282
|
_task_port = int(getattr(_task_state, "active_port", 0) or 0)
|
|
1263
1283
|
content = ground_run_or_launch_text(content, _task_port)
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"""Tier-2 verification: run the project's OWN typecheck/lint once, return errors.
|
|
2
|
+
|
|
3
|
+
The big agents catch semantic errors with a persistent language server (LSP).
|
|
4
|
+
opencode's own docs say that for many projects it's better to run the project's
|
|
5
|
+
diagnostic CLI directly — LSPs "get out of sync, use significant memory … and
|
|
6
|
+
slow down agent workflows." That's decisive for localcode: a 16 GB Mac already
|
|
7
|
+
running a large local model can't spare an always-on tsserver/pyright.
|
|
8
|
+
|
|
9
|
+
So instead we run the project's real typecheck ONCE, when the model is about to
|
|
10
|
+
finish an unverified build, and feed the concrete errors back deterministically
|
|
11
|
+
(the model can't skip it, and gets ground truth like "line 37: 'getCardsForCard'
|
|
12
|
+
does not exist" — the semantic errors a per-write syntax check can't catch).
|
|
13
|
+
|
|
14
|
+
Light: one bounded subprocess at completion, not per-edit. Returns None when the
|
|
15
|
+
project is clean or no checker is available.
|
|
16
|
+
"""
|
|
17
|
+
from __future__ import annotations
|
|
18
|
+
|
|
19
|
+
import json
|
|
20
|
+
import os
|
|
21
|
+
import re
|
|
22
|
+
import shutil
|
|
23
|
+
import subprocess
|
|
24
|
+
|
|
25
|
+
_TIMEOUT = 60.0
|
|
26
|
+
_MAX_ERR_CHARS = 2500
|
|
27
|
+
_ANSI = re.compile(r"\x1b\[[0-9;]*m")
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def run_project_check(repo_root: str) -> str | None:
|
|
31
|
+
"""Run the first available typecheck/lint for the project; return a bounded
|
|
32
|
+
error summary, or None if clean / nothing to run."""
|
|
33
|
+
env = {**os.environ, "NO_COLOR": "1", "FORCE_COLOR": "0"}
|
|
34
|
+
for label, argv, cwd in _detect_commands(repo_root):
|
|
35
|
+
try:
|
|
36
|
+
r = subprocess.run(
|
|
37
|
+
argv, cwd=cwd, capture_output=True, text=True,
|
|
38
|
+
timeout=_TIMEOUT, env=env,
|
|
39
|
+
)
|
|
40
|
+
except Exception:
|
|
41
|
+
continue
|
|
42
|
+
if r.returncode != 0:
|
|
43
|
+
out = _ANSI.sub("", ((r.stdout or "") + "\n" + (r.stderr or "")).strip())
|
|
44
|
+
# Keep only the most useful lines, capped, so we don't flood a
|
|
45
|
+
# small model's context with a wall of output.
|
|
46
|
+
lines = [l for l in out.splitlines() if l.strip()][:40]
|
|
47
|
+
if lines:
|
|
48
|
+
return f"[{label}] reported errors:\n" + "\n".join(lines)[:_MAX_ERR_CHARS]
|
|
49
|
+
return None
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _detect_commands(repo_root: str) -> list[tuple[str, list[str], str]]:
|
|
53
|
+
"""Ordered (label, argv, cwd) checkers to try. First that runs wins."""
|
|
54
|
+
cmds: list[tuple[str, list[str], str]] = []
|
|
55
|
+
|
|
56
|
+
# ── JS / TS ── prefer a project "typecheck" script, else tsc --noEmit.
|
|
57
|
+
pj_dir = _nearest_with(repo_root, "package.json")
|
|
58
|
+
if pj_dir:
|
|
59
|
+
node_modules = os.path.join(pj_dir, "node_modules")
|
|
60
|
+
binp = os.path.join(node_modules, ".bin")
|
|
61
|
+
scripts = {}
|
|
62
|
+
try:
|
|
63
|
+
scripts = (json.load(open(os.path.join(pj_dir, "package.json"))) or {}).get("scripts", {})
|
|
64
|
+
except Exception:
|
|
65
|
+
scripts = {}
|
|
66
|
+
# Only run node-based checks once deps are installed (else every import
|
|
67
|
+
# is a false "cannot find module" error that would derail the model).
|
|
68
|
+
if os.path.isdir(node_modules):
|
|
69
|
+
if "typecheck" in scripts:
|
|
70
|
+
cmds.append(("npm run typecheck", ["npm", "run", "--silent", "typecheck"], pj_dir))
|
|
71
|
+
elif os.path.exists(os.path.join(pj_dir, "tsconfig.json")) and os.path.exists(os.path.join(binp, "tsc")):
|
|
72
|
+
cmds.append(("tsc --noEmit", [os.path.join(binp, "tsc"), "--noEmit", "--pretty", "false"], pj_dir))
|
|
73
|
+
elif "lint" in scripts:
|
|
74
|
+
cmds.append(("npm run lint", ["npm", "run", "--silent", "lint"], pj_dir))
|
|
75
|
+
|
|
76
|
+
# ── Python ── ruff for REAL errors only (E9 syntax + F pyflakes: undefined
|
|
77
|
+
# names, bad imports) — not style noise. Falls back to compileall (syntax).
|
|
78
|
+
if _has_ext(repo_root, ".py"):
|
|
79
|
+
if shutil.which("ruff"):
|
|
80
|
+
cmds.append(("ruff", ["ruff", "check", "--select", "E9,F",
|
|
81
|
+
"--no-cache", "--output-format", "concise", "."], repo_root))
|
|
82
|
+
elif shutil.which("python3") or shutil.which("python"):
|
|
83
|
+
py = shutil.which("python3") or shutil.which("python")
|
|
84
|
+
cmds.append(("python -m compileall", [py, "-m", "compileall", "-q", "."], repo_root))
|
|
85
|
+
|
|
86
|
+
# ── Go ── the compiler catches type/undefined errors (like tsc). go.mod.
|
|
87
|
+
go_dir = _nearest_with(repo_root, "go.mod")
|
|
88
|
+
if go_dir and shutil.which("go"):
|
|
89
|
+
cmds.append(("go build", ["go", "build", "./..."], go_dir))
|
|
90
|
+
|
|
91
|
+
# ── Rust ── cargo check is the type-checker (fast, no codegen). Cargo.toml.
|
|
92
|
+
rust_dir = _nearest_with(repo_root, "Cargo.toml")
|
|
93
|
+
if rust_dir and shutil.which("cargo"):
|
|
94
|
+
cmds.append(("cargo check", ["cargo", "check", "--message-format", "short"], rust_dir))
|
|
95
|
+
|
|
96
|
+
# (Interpreted langs — Ruby/PHP/shell — have no whole-project type-check;
|
|
97
|
+
# their per-file syntax linters run in the Tier-1 syntax_check on each write.)
|
|
98
|
+
return cmds
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _nearest_with(root: str, filename: str) -> str | None:
|
|
102
|
+
"""The shallowest directory under root that contains `filename`."""
|
|
103
|
+
root = os.path.abspath(root)
|
|
104
|
+
if os.path.exists(os.path.join(root, filename)):
|
|
105
|
+
return root
|
|
106
|
+
for base, dirs, files in os.walk(root):
|
|
107
|
+
dirs[:] = [d for d in dirs if d not in (".git", "node_modules", "dist", "build", ".venv")]
|
|
108
|
+
if filename in files:
|
|
109
|
+
return base
|
|
110
|
+
return None
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _has_ext(root: str, ext: str) -> bool:
|
|
114
|
+
for base, dirs, files in os.walk(os.path.abspath(root)):
|
|
115
|
+
dirs[:] = [d for d in dirs if d not in (".git", "node_modules", "dist", "build", ".venv")]
|
|
116
|
+
if any(f.endswith(ext) for f in files):
|
|
117
|
+
return True
|
|
118
|
+
return False
|
localcode/tools/syntax_check.py
CHANGED
|
@@ -1,23 +1,22 @@
|
|
|
1
|
-
"""One-shot syntax validation for files the agent writes.
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
`
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
with LOCALCODE_SYNTAX_CHECK=0.
|
|
1
|
+
"""One-shot syntax validation for files the agent writes — in-process, offline.
|
|
2
|
+
|
|
3
|
+
Tier-1 verification. The big agents use a persistent language server (LSP);
|
|
4
|
+
opencode's own docs say that's often worse than running diagnostics directly
|
|
5
|
+
(LSPs "get out of sync, use significant memory, slow down agent workflows") —
|
|
6
|
+
decisive for a 16 GB Mac already running a large local model.
|
|
7
|
+
|
|
8
|
+
Crucially this must work with NO tools the user has to install and NO network:
|
|
9
|
+
it's bundled. We parse with tree-sitter (grammars compiled into the wheel — one
|
|
10
|
+
~4.5 MB native extension covering 100+ languages) and flag any syntax error
|
|
11
|
+
in-process. So when a small quantized model drifts into a structural typo
|
|
12
|
+
(`useState(0]`, an unterminated string, a missing bracket), the write tool
|
|
13
|
+
appends the exact error and line, and the model fixes THAT line instead of
|
|
14
|
+
re-reading the broken file and reproducing the error (the self-conditioning
|
|
15
|
+
loop). Python/JSON keep their native checkers for sharper messages.
|
|
16
|
+
|
|
17
|
+
Semantic/type errors (wrong names, missing imports) are caught separately by
|
|
18
|
+
project_check at completion (tsc/ruff/go/cargo). Disable with
|
|
19
|
+
LOCALCODE_SYNTAX_CHECK=0.
|
|
21
20
|
"""
|
|
22
21
|
from __future__ import annotations
|
|
23
22
|
|
|
@@ -27,25 +26,34 @@ import subprocess
|
|
|
27
26
|
|
|
28
27
|
_TIMEOUT = 5.0
|
|
29
28
|
|
|
29
|
+
# File extension → tree-sitter language name (all bundled in the language pack).
|
|
30
|
+
_TS_LANG = {
|
|
31
|
+
".js": "javascript", ".mjs": "javascript", ".cjs": "javascript",
|
|
32
|
+
".jsx": "tsx", ".ts": "typescript", ".mts": "typescript", ".cts": "typescript",
|
|
33
|
+
".tsx": "tsx", ".go": "go", ".rs": "rust", ".rb": "ruby", ".php": "php",
|
|
34
|
+
".sh": "bash", ".bash": "bash", ".zsh": "bash", ".lua": "lua",
|
|
35
|
+
".c": "c", ".h": "c", ".cpp": "cpp", ".cc": "cpp", ".cxx": "cpp",
|
|
36
|
+
".hpp": "cpp", ".hh": "cpp", ".java": "java", ".kt": "kotlin",
|
|
37
|
+
".swift": "swift", ".cs": "csharp", ".scala": "scala",
|
|
38
|
+
".css": "css", ".scss": "scss", ".html": "html", ".xml": "xml",
|
|
39
|
+
".yaml": "yaml", ".yml": "yaml", ".toml": "toml", ".sql": "sql",
|
|
40
|
+
}
|
|
30
41
|
|
|
31
|
-
def check_syntax(path: str, content: str) -> str | None:
|
|
32
|
-
"""Return a one-line syntax-error string, or None if OK / not checkable.
|
|
33
42
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
"""
|
|
43
|
+
def check_syntax(path: str, content: str) -> str | None:
|
|
44
|
+
"""Return a one-line syntax-error string, or None if OK / not checkable."""
|
|
37
45
|
if os.environ.get("LOCALCODE_SYNTAX_CHECK") == "0":
|
|
38
46
|
return None
|
|
39
47
|
ext = os.path.splitext(path)[1].lower()
|
|
40
48
|
try:
|
|
49
|
+
# Native checkers give the sharpest messages; use them where free.
|
|
41
50
|
if ext == ".json":
|
|
42
51
|
return _check_json(content)
|
|
43
52
|
if ext in (".py", ".pyi"):
|
|
44
53
|
return _check_python(content, path)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
return _check_esbuild(path)
|
|
54
|
+
lang = _TS_LANG.get(ext)
|
|
55
|
+
if lang:
|
|
56
|
+
return _check_treesitter(content, lang)
|
|
49
57
|
except Exception:
|
|
50
58
|
return None
|
|
51
59
|
return None
|
|
@@ -68,66 +76,47 @@ def _check_python(content: str, path: str) -> str | None:
|
|
|
68
76
|
return f"Python syntax error at {loc}: {e.msg}"
|
|
69
77
|
|
|
70
78
|
|
|
71
|
-
def
|
|
72
|
-
|
|
73
|
-
if not shutil.which("node"):
|
|
74
|
-
return None
|
|
75
|
-
r = subprocess.run(
|
|
76
|
-
["node", "--check", path],
|
|
77
|
-
capture_output=True, text=True, timeout=_TIMEOUT,
|
|
78
|
-
)
|
|
79
|
-
if r.returncode != 0:
|
|
80
|
-
return _first_error_line(r.stderr)
|
|
81
|
-
return None
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
def _find_bin(start: str, name: str) -> str | None:
|
|
85
|
-
"""Walk up from the file's dir to find node_modules/.bin/<name>."""
|
|
86
|
-
d = os.path.dirname(os.path.abspath(start))
|
|
87
|
-
for _ in range(25):
|
|
88
|
-
cand = os.path.join(d, "node_modules", ".bin", name)
|
|
89
|
-
if os.path.exists(cand):
|
|
90
|
-
return cand
|
|
91
|
-
parent = os.path.dirname(d)
|
|
92
|
-
if parent == d:
|
|
93
|
-
break
|
|
94
|
-
d = parent
|
|
95
|
-
return None
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
def _check_esbuild(path: str) -> str | None:
|
|
99
|
-
# esbuild parses TS/TSX/JSX and reports syntax errors instantly. Only used
|
|
100
|
-
# when the project has it (Vite/most JS projects do post-install); if not
|
|
101
|
-
# present we skip rather than risk a false alarm from a wrong parser.
|
|
102
|
-
esbuild = _find_bin(path, "esbuild")
|
|
103
|
-
if not esbuild:
|
|
104
|
-
return None
|
|
105
|
-
loader = "tsx" if path.endswith((".tsx", ".jsx")) else "ts"
|
|
106
|
-
r = subprocess.run(
|
|
107
|
-
[esbuild, path, f"--loader={loader}", "--log-level=error"],
|
|
108
|
-
capture_output=True, text=True, timeout=_TIMEOUT,
|
|
109
|
-
)
|
|
110
|
-
if r.returncode != 0 and r.stderr.strip():
|
|
111
|
-
return _first_error_line(r.stderr)
|
|
112
|
-
return None
|
|
79
|
+
def _check_treesitter(content: str, lang: str) -> str | None:
|
|
80
|
+
"""Parse with a bundled tree-sitter grammar; report the first syntax error.
|
|
113
81
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
"""Pull the human-meaningful error out of a node/esbuild stderr dump.
|
|
117
|
-
|
|
118
|
-
Prefer the actual `SyntaxError: …` / `error: …` message, skipping node's
|
|
119
|
-
internal loader/stack frames (`node:internal/…`, ` at …`).
|
|
82
|
+
No external tools, no network — the grammars are compiled into the wheel.
|
|
83
|
+
Returns None if tree-sitter isn't available (graceful) or the file parses.
|
|
120
84
|
"""
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
85
|
+
try:
|
|
86
|
+
from tree_sitter_language_pack import get_language
|
|
87
|
+
from tree_sitter import Parser
|
|
88
|
+
except Exception:
|
|
89
|
+
return None
|
|
90
|
+
try:
|
|
91
|
+
parser = Parser(get_language(lang))
|
|
92
|
+
tree = parser.parse(content.encode("utf-8"))
|
|
93
|
+
except Exception:
|
|
94
|
+
return None
|
|
95
|
+
root = tree.root_node
|
|
96
|
+
if not root.has_error:
|
|
97
|
+
return None
|
|
98
|
+
node = _first_error_node(root)
|
|
99
|
+
if node is None:
|
|
100
|
+
return f"syntax error detected in this {lang} file (unbalanced brackets/quotes or a stray token)"
|
|
101
|
+
line = node.start_point[0] + 1
|
|
102
|
+
col = node.start_point[1] + 1
|
|
103
|
+
snippet = ""
|
|
104
|
+
try:
|
|
105
|
+
src_line = content.splitlines()[node.start_point[0]].strip()
|
|
106
|
+
snippet = f" — near: {src_line[:80]}"
|
|
107
|
+
except Exception:
|
|
108
|
+
snippet = ""
|
|
109
|
+
kind = "missing token" if node.is_missing else "unexpected token"
|
|
110
|
+
return f"syntax error (line {line} col {col}): {kind}{snippet}"
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _first_error_node(root):
|
|
114
|
+
"""DFS for the first ERROR or MISSING node (the actual syntax fault)."""
|
|
115
|
+
stack = [root]
|
|
116
|
+
while stack:
|
|
117
|
+
n = stack.pop()
|
|
118
|
+
if n.is_error or n.is_missing:
|
|
119
|
+
return n
|
|
120
|
+
# push children in order so we return the earliest error
|
|
121
|
+
stack.extend(reversed(n.children))
|
|
133
122
|
return None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: localcode
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.9
|
|
4
4
|
Summary: High-performance AI coding on consumer hardware.
|
|
5
5
|
Author: LocalCode contributors
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -35,6 +35,8 @@ Requires-Dist: prompt_toolkit>=3.0.52
|
|
|
35
35
|
Requires-Dist: rich>=13.7.1
|
|
36
36
|
Requires-Dist: scikit-learn>=1.3.0
|
|
37
37
|
Requires-Dist: textual>=8.2.4
|
|
38
|
+
Requires-Dist: tree-sitter>=0.23.0
|
|
39
|
+
Requires-Dist: tree-sitter-language-pack>=1.0.0
|
|
38
40
|
Requires-Dist: tomli>=2.0.0; python_version < "3.11"
|
|
39
41
|
Provides-Extra: voice
|
|
40
42
|
Requires-Dist: pywhispercpp>=1.2.0; extra == "voice"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
localcode/__init__.py,sha256=
|
|
1
|
+
localcode/__init__.py,sha256=dv_OdIY5KS_HiRjBMSmtKnar5Axf3OVYIDjhWUodlAY,49
|
|
2
2
|
localcode/__main__.py,sha256=_4Tblte9F1KOpB-oGBQuTlaSN-IncLmhihqhBkpH3pU,69
|
|
3
3
|
localcode/_subproc_env.py,sha256=eltq_kKvqGj22pIFivB5BZft9-s5fziBW0lsV9FhEV4,2383
|
|
4
4
|
localcode/app.py,sha256=FSwpce6Jfn7zJmhL1ipaqTq0xKh0MxCMnEnMQuFV8L8,67820
|
|
@@ -71,7 +71,7 @@ localcode/agent/context.py,sha256=adV_WlFBHMDHsWdndRgrkZqRweDD9plyqMP_2X74WAw,37
|
|
|
71
71
|
localcode/agent/goal.py,sha256=X87Q3rsdp70wOfkpbh35M4qFWSNyklX3RuRWjv-pCXs,6264
|
|
72
72
|
localcode/agent/helpers.py,sha256=vutFyCtnca0UnF0wgk7LdsqVWdiqyYm4YnFOxtnCJ_A,15004
|
|
73
73
|
localcode/agent/hooks.py,sha256=XadEbSM7gHtKlLrqSKnvcQFcoWoNUXdlMdIPS-EwBGA,15841
|
|
74
|
-
localcode/agent/loop.py,sha256=
|
|
74
|
+
localcode/agent/loop.py,sha256=Gp4Zt0fRpQkE1YLZjrF9xtzM4qlJodyFeGGupx_U16k,101105
|
|
75
75
|
localcode/agent/prompt_context.py,sha256=abJPLMhTzuVcsW4AfMBIW-SEqmrU69DhI-0vGZllZVU,13707
|
|
76
76
|
localcode/agent/prompts.py,sha256=LCJBM2mV_SKc1OXtH0-ih9OPQnhrTh3vTlrOgLUiVDA,14845
|
|
77
77
|
localcode/agent/recovery.py,sha256=-2vnYhhUGZD_reR6CaMOYNsG5XRf6YDsjTqF-1P-St4,16831
|
|
@@ -109,9 +109,10 @@ localcode/tools/launch_app.py,sha256=TVoq1ZQEIm2yQ607LGkJwbIC3TkvaLsBpTJgYIGX1gM
|
|
|
109
109
|
localcode/tools/list_files.py,sha256=wN2dXU01rrKB_HGh6i0GfM9qvBwx7Qoa3S5WZlArma0,1205
|
|
110
110
|
localcode/tools/multi_edit.py,sha256=WkGibiGkr_J-Ld4CtxR24icdy1kGQuPEh6kKDrKe8Ss,4780
|
|
111
111
|
localcode/tools/plan_mode.py,sha256=2RU6QH1IJoOTKuoAr7Ga7uTaebAS8v7OFt5v1zLEXFw,2886
|
|
112
|
+
localcode/tools/project_check.py,sha256=B3Q6IB2XfllW3Nlxwz2pCCQwF_b0VSUBnrpCHS4eOE8,5508
|
|
112
113
|
localcode/tools/read_file.py,sha256=gH852nnPiVD2Go9VcdS_EFbtnqYaGOPyAk5jo1cNbX8,4556
|
|
113
114
|
localcode/tools/skill_tool.py,sha256=vTVPyRWxICtDCVYWMiAMInGnc-wGAk2L1EZn-6e79nE,1478
|
|
114
|
-
localcode/tools/syntax_check.py,sha256=
|
|
115
|
+
localcode/tools/syntax_check.py,sha256=tpymYFeXs7LYU5qmfHGJeVX0WUdFYBineI9GN3jONYU,4726
|
|
115
116
|
localcode/tools/todo_write.py,sha256=8A4k9MzoqOtzJ6y2Gd3lEGkINcpV3JVCd2lYBmdd6qI,5801
|
|
116
117
|
localcode/tools/web_fetch.py,sha256=UPhMrLipwN5xJx5-zr634gL4p6nIRqYI2_7tbUw_8Go,2770
|
|
117
118
|
localcode/tools/web_search.py,sha256=ILfBBx50p00OjA939HzdDmdao4QLL8sRuxlBoUDjmC8,1122
|
|
@@ -132,9 +133,9 @@ localcode/tui/widgets/chat_log.py,sha256=D5DUkrQXL_ilxyC8N1xIPLw4Pqeh0jSWt1mPgho
|
|
|
132
133
|
localcode/tui/widgets/voice_visualizer.py,sha256=zOhrIxaMcg-F2Y8LvHJTddq227phmiTjtEyRbkx1XxU,4709
|
|
133
134
|
localcode/tui/widgets/messages/__init__.py,sha256=952AZ1qVMGUIqPIry7mwxnYbMkgPlcY5FAwZtEa5YPg,967
|
|
134
135
|
localcode/tui/widgets/messages/diff.py,sha256=khDf_MThrQz0S62-t-m7i3OU5cdNolUk1TCeKMRPDQI,10910
|
|
135
|
-
localcode-0.3.
|
|
136
|
-
localcode-0.3.
|
|
137
|
-
localcode-0.3.
|
|
138
|
-
localcode-0.3.
|
|
139
|
-
localcode-0.3.
|
|
140
|
-
localcode-0.3.
|
|
136
|
+
localcode-0.3.9.dist-info/licenses/LICENSE,sha256=Ahg0cteZ-6bIRB7KC15WEtdqWnzy8HY_yzsZBoVRql0,11294
|
|
137
|
+
localcode-0.3.9.dist-info/METADATA,sha256=iT5SYY0r4-zju8UthKU8MTPF4w_3HRk0H11CIB_8dQ0,7896
|
|
138
|
+
localcode-0.3.9.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
|
|
139
|
+
localcode-0.3.9.dist-info/entry_points.txt,sha256=rE7elTGUvMsBd-Quy22cuTVJ-zGVOmx0nEuC6ni9Tg4,87
|
|
140
|
+
localcode-0.3.9.dist-info/top_level.txt,sha256=58eL3Rw8v0OGmYNxjx8uS4ERWatrzUbyCL5inlukkTo,10
|
|
141
|
+
localcode-0.3.9.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|