lcode-cli 0.31.0__py3-none-any.whl → 0.32.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.
- lcode/__init__.py +1 -1
- lcode/agent.py +54 -0
- lcode/api.py +3 -0
- lcode/cli.py +4 -0
- lcode/config.py +1 -0
- lcode/review.py +103 -0
- lcode/tools.py +3 -0
- {lcode_cli-0.31.0.dist-info → lcode_cli-0.32.0.dist-info}/METADATA +1 -1
- {lcode_cli-0.31.0.dist-info → lcode_cli-0.32.0.dist-info}/RECORD +12 -11
- {lcode_cli-0.31.0.dist-info → lcode_cli-0.32.0.dist-info}/WHEEL +0 -0
- {lcode_cli-0.31.0.dist-info → lcode_cli-0.32.0.dist-info}/entry_points.txt +0 -0
- {lcode_cli-0.31.0.dist-info → lcode_cli-0.32.0.dist-info}/licenses/LICENSE +0 -0
lcode/__init__.py
CHANGED
lcode/agent.py
CHANGED
|
@@ -35,6 +35,7 @@ from lcode import (
|
|
|
35
35
|
planning,
|
|
36
36
|
repomap,
|
|
37
37
|
residency,
|
|
38
|
+
review,
|
|
38
39
|
sessions,
|
|
39
40
|
subagents,
|
|
40
41
|
vision,
|
|
@@ -276,6 +277,7 @@ class Settings:
|
|
|
276
277
|
compact_at: int = 0 # tokens: make room at this size even when the window is larger (0: only at 85%)
|
|
277
278
|
repeat_limit: int = 3 # identical calls with identical results before the model is told (lcode.repeats)
|
|
278
279
|
checks: str = "off" # the project's checks after a change (lcode.checks): auto, off or a command
|
|
280
|
+
review: str = "off" # check a change against the request before the answer (lcode.review): auto or off
|
|
279
281
|
|
|
280
282
|
|
|
281
283
|
class Agent:
|
|
@@ -334,6 +336,7 @@ class Agent:
|
|
|
334
336
|
self.autosave = False # save the session after every step (sessions people resume; not the bench's)
|
|
335
337
|
self._check: tuple[Path, checks.Check | None] | None = None
|
|
336
338
|
self.check_results: list[dict] = [] # the checks of the last request: command, exit code, who ran them
|
|
339
|
+
self.review_results: list[str] | None = None # what the last request's review found (None: no review)
|
|
337
340
|
self.sent_chars = 0 # characters of the conversation the model had already read
|
|
338
341
|
self.counted_chars: int | None = None # characters that ctx_used covers (None: all of them)
|
|
339
342
|
self.turn_status = "" # how the last request ended: success, max_steps, loop
|
|
@@ -831,6 +834,48 @@ class Agent:
|
|
|
831
834
|
self.last_speed = final.get("eval_count", 0) / seconds if seconds else 0.0
|
|
832
835
|
return message
|
|
833
836
|
|
|
837
|
+
def reviewing(self) -> bool:
|
|
838
|
+
return (
|
|
839
|
+
self.settings.review != "off" and self.allowed_tools is None and not self.planning() and not self.no_changes
|
|
840
|
+
)
|
|
841
|
+
|
|
842
|
+
def self_review(self, answer: str) -> list[str]:
|
|
843
|
+
"""Check the request's change against the request before the answer counts; the problems found."""
|
|
844
|
+
budget = int(self.settings.context * 3 * 0.25)
|
|
845
|
+
diff, changed = review.diff_of(self.tools.before, self.current_text, budget)
|
|
846
|
+
if changed < review.MIN_CHANGED_LINES:
|
|
847
|
+
return []
|
|
848
|
+
request = next(
|
|
849
|
+
(
|
|
850
|
+
context_tools.request_text(str(m.get("content", "")))
|
|
851
|
+
for m in reversed(self.messages)
|
|
852
|
+
if m.get("role") == "user"
|
|
853
|
+
and not str(m.get("content", "")).startswith(("[lcode]", sessions.SUMMARY_PREFIX))
|
|
854
|
+
),
|
|
855
|
+
"",
|
|
856
|
+
)
|
|
857
|
+
try:
|
|
858
|
+
with self.console.status("Reviewing the change against your request…", spinner="dots"):
|
|
859
|
+
problems = review.run(self, request, answer, diff)
|
|
860
|
+
except OllamaError as e:
|
|
861
|
+
self.say(f"The review didn't run: {e}", warning=True)
|
|
862
|
+
return []
|
|
863
|
+
self.review_results = problems
|
|
864
|
+
if problems:
|
|
865
|
+
self.say(
|
|
866
|
+
f"Review: {len(problems)} point(s) sent back to the model. First: {problems[0][:160]}", warning=True
|
|
867
|
+
)
|
|
868
|
+
else:
|
|
869
|
+
self.say("Review: the change does what was asked.")
|
|
870
|
+
return problems
|
|
871
|
+
|
|
872
|
+
def current_text(self, path: str) -> str | None:
|
|
873
|
+
p = self.tools.resolve(path)
|
|
874
|
+
try:
|
|
875
|
+
return self.tools.read_text(p) if p.is_file() else None
|
|
876
|
+
except OSError:
|
|
877
|
+
return None
|
|
878
|
+
|
|
834
879
|
def checks_prompt(self) -> str:
|
|
835
880
|
check = self.project_check()
|
|
836
881
|
if check is None:
|
|
@@ -1026,6 +1071,9 @@ class Agent:
|
|
|
1026
1071
|
self.messages.append({"role": "user", "content": self.expand_mentions(user_text) + note})
|
|
1027
1072
|
self.repeats.reset()
|
|
1028
1073
|
self.check_results = []
|
|
1074
|
+
self.review_results = None
|
|
1075
|
+
self.tools.before = {}
|
|
1076
|
+
reviewed = False
|
|
1029
1077
|
changed = verified = False # files changed in this request; the checks passed since
|
|
1030
1078
|
check_rounds = 0
|
|
1031
1079
|
malformed = 0
|
|
@@ -1087,6 +1135,12 @@ class Agent:
|
|
|
1087
1135
|
changed = False # run them again only if the model changes something more
|
|
1088
1136
|
continue
|
|
1089
1137
|
verified = True
|
|
1138
|
+
if not reviewed and self.tools.before and self.reviewing():
|
|
1139
|
+
reviewed = True
|
|
1140
|
+
problems = self.self_review(reply.get("content") or "")
|
|
1141
|
+
if problems:
|
|
1142
|
+
self.messages.append({"role": "user", "content": review.feedback(problems)})
|
|
1143
|
+
continue
|
|
1090
1144
|
break
|
|
1091
1145
|
done: dict[int, str] = {} # results of subagents that ran together
|
|
1092
1146
|
together = [
|
lcode/api.py
CHANGED
|
@@ -77,6 +77,7 @@ class Result:
|
|
|
77
77
|
files_changed: list[dict] = field(default_factory=list) # {"status": "A" | "M" | "D", "path"}
|
|
78
78
|
usage: dict = field(default_factory=dict) # requests, prompt_tokens, output_tokens
|
|
79
79
|
checks: list[dict] = field(default_factory=list) # {"command", "exit_code", "by": "lcode" | "model"}
|
|
80
|
+
review: list[str] | None = None # problems the review sent back ([] when it found none; None: no review)
|
|
80
81
|
seconds: float = 0.0
|
|
81
82
|
error: str = ""
|
|
82
83
|
|
|
@@ -198,6 +199,7 @@ def open_agent(cwd: Path, options: Options, console: Console, hw: Hardware | Non
|
|
|
198
199
|
secret_check=cfg["secret_check"],
|
|
199
200
|
repeat_limit=cfg["repeat_limit"],
|
|
200
201
|
checks=cfg["checks"],
|
|
202
|
+
review=cfg["review"],
|
|
201
203
|
compact_at=cfg["compact_at"],
|
|
202
204
|
)
|
|
203
205
|
agent = Agent(ollama, settings, cwd, console=console)
|
|
@@ -306,6 +308,7 @@ def run_request(agent: Agent, prompt: str) -> Result:
|
|
|
306
308
|
files_changed=files,
|
|
307
309
|
usage=usage,
|
|
308
310
|
checks=list(agent.check_results),
|
|
311
|
+
review=agent.review_results,
|
|
309
312
|
seconds=round(time.monotonic() - started, 2),
|
|
310
313
|
error=error,
|
|
311
314
|
)
|
lcode/cli.py
CHANGED
|
@@ -581,6 +581,7 @@ def cmd_bench(args) -> None:
|
|
|
581
581
|
prune=not args.no_prune,
|
|
582
582
|
compact_at=cfg["compact_at"] if args.compact_at is None else args.compact_at,
|
|
583
583
|
checks=cfg["checks"] if args.checks is None else args.checks,
|
|
584
|
+
review=cfg["review"] if args.review is None else args.review,
|
|
584
585
|
repo_map=args.repo_map,
|
|
585
586
|
embed_model=cfg["embed_model"] if args.code_search else "off",
|
|
586
587
|
)
|
|
@@ -775,6 +776,9 @@ def build_subparsers() -> dict[str, argparse.ArgumentParser]:
|
|
|
775
776
|
p.add_argument("--repo-map", action="store_true", help="give the model the repository map (off by default)")
|
|
776
777
|
p.add_argument("--code-search", action="store_true", help="index each task's folder and offer semantic code search")
|
|
777
778
|
p.add_argument("--no-prune", action="store_true", help="don't remove old tool output (to compare, with --session)")
|
|
779
|
+
p.add_argument(
|
|
780
|
+
"--review", choices=["auto", "off"], help="review each change before it counts (default: the setting)"
|
|
781
|
+
)
|
|
778
782
|
p.add_argument(
|
|
779
783
|
"--checks",
|
|
780
784
|
metavar="auto|off|COMMAND",
|
lcode/config.py
CHANGED
|
@@ -59,6 +59,7 @@ SETTINGS: dict[str, tuple[object, type, str]] = {
|
|
|
59
59
|
"subagents": (True, bool, "let the model hand tasks to subagents that have their own context"),
|
|
60
60
|
"notify": (True, bool, "desktop notification when a long request is done or waits for you"),
|
|
61
61
|
"notify_after": (30, int, "seconds a request runs before it notifies (with notify on)"),
|
|
62
|
+
"review": ("off", str, "before the answer, check a change against the request and send problems back: auto | off"),
|
|
62
63
|
"checks": ("auto", str, "run the project's checks before calling work done: auto | off | a command"),
|
|
63
64
|
"repeat_limit": (3, int, "identical tool calls with identical results before lcode steps in (0: never)"),
|
|
64
65
|
"secret_check": (True, bool, "before git commit and git push, look for passwords, keys and tokens they'd add"),
|
lcode/review.py
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
"""A second look at a change before the answer goes to the user.
|
|
2
|
+
|
|
3
|
+
Models claim more than they did: "users can now shrink the window" without having checked, half of a
|
|
4
|
+
two-part request done, a debug print left behind. So when a request changed files, lcode asks the model to
|
|
5
|
+
step back and check its change against the request (what was asked, what the diff shows, what the answer
|
|
6
|
+
claims) before the answer counts. Real problems go back to the model once; the user sees a line about it.
|
|
7
|
+
|
|
8
|
+
The review is asked on top of the conversation, not in a fresh one: the model server keeps the processed
|
|
9
|
+
conversation cached, and a separate review prompt would push it out, so the next step would have to read the
|
|
10
|
+
whole conversation again, tens of seconds on a small GPU. The question tells the model to judge only from the
|
|
11
|
+
request and the diff.
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from __future__ import annotations
|
|
15
|
+
|
|
16
|
+
import difflib
|
|
17
|
+
from typing import TYPE_CHECKING
|
|
18
|
+
|
|
19
|
+
from lcode.gitflow import parse_json
|
|
20
|
+
|
|
21
|
+
if TYPE_CHECKING:
|
|
22
|
+
from lcode.agent import Agent
|
|
23
|
+
|
|
24
|
+
MIN_CHANGED_LINES = 1 # even one line: a one-line bug fix is where a wrong fix hides
|
|
25
|
+
MAX_PROBLEMS = 5
|
|
26
|
+
SCHEMA = {
|
|
27
|
+
"type": "object",
|
|
28
|
+
"properties": {"problems": {"type": "array", "items": {"type": "string"}}},
|
|
29
|
+
"required": ["problems"],
|
|
30
|
+
}
|
|
31
|
+
PROMPT = """[lcode] Before your answer goes to the user, review your change as a strict reviewer would: judge it only by what the user asked and what the diff shows, not by what you meant to do.
|
|
32
|
+
|
|
33
|
+
The user's request:
|
|
34
|
+
<request>
|
|
35
|
+
{request}
|
|
36
|
+
</request>
|
|
37
|
+
|
|
38
|
+
Your answer to them:
|
|
39
|
+
<answer>
|
|
40
|
+
{answer}
|
|
41
|
+
</answer>
|
|
42
|
+
|
|
43
|
+
{checks}The change (unified diff of the files changed in this request):
|
|
44
|
+
<diff>
|
|
45
|
+
{diff}
|
|
46
|
+
</diff>
|
|
47
|
+
|
|
48
|
+
Find real problems only, each one you can point to in the request or the diff:
|
|
49
|
+
1. Something the user asked for that the change doesn't do, or only partly does.
|
|
50
|
+
2. A claim in your answer that the diff doesn't support, or something called tested or working that nothing shows was run.
|
|
51
|
+
3. A mistake in the diff: a bug, a broken edge case the request mentions, leftover debugging (prints, commented-out code), an unfinished TODO.
|
|
52
|
+
No style preferences, no suggestions beyond the request. Answer in JSON: {{"problems": ["…"]}}, with an empty list when the change does what was asked."""
|
|
53
|
+
|
|
54
|
+
FEEDBACK = """[lcode] A review of your change against the user's request found:
|
|
55
|
+
{problems}
|
|
56
|
+
|
|
57
|
+
Fix what's real; if a point is wrong, say why in your answer. Then finish."""
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def diff_of(before: dict[str, str | None], read, budget: int) -> tuple[str, int]:
|
|
61
|
+
"""The unified diff of the files changed in the request, and how many lines it changes."""
|
|
62
|
+
parts, changed = [], 0
|
|
63
|
+
for path, old in before.items():
|
|
64
|
+
new = read(path)
|
|
65
|
+
if new is None or new == old:
|
|
66
|
+
continue
|
|
67
|
+
lines = list(
|
|
68
|
+
difflib.unified_diff((old or "").splitlines(True), new.splitlines(True), f"a/{path}", f"b/{path}", n=2)
|
|
69
|
+
)
|
|
70
|
+
changed += sum(1 for line in lines if line[:1] in "+-" and not line.startswith(("+++", "---")))
|
|
71
|
+
parts.append("".join(lines))
|
|
72
|
+
text = "".join(parts)
|
|
73
|
+
if len(text) > budget:
|
|
74
|
+
text = text[:budget] + f"\n[… the rest of the diff ({len(text) - budget} characters) is cut]"
|
|
75
|
+
return text, changed
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def run(agent: Agent, request: str, answer: str, diff: str) -> list[str]:
|
|
79
|
+
"""Ask for the review; the problems it found (empty when none, or when the answer can't be read)."""
|
|
80
|
+
checks = ""
|
|
81
|
+
if agent.check_results:
|
|
82
|
+
last = agent.check_results[-1]
|
|
83
|
+
code = last.get("exit_code")
|
|
84
|
+
state = "passed" if code == 0 else "didn't run" if code is None else f"failed (exit code {code})"
|
|
85
|
+
checks = f"The project's checks (`{last.get('command')}`) {state} after the change.\n\n"
|
|
86
|
+
prompt = PROMPT.format(request=request[:4000], answer=answer[:3000] or "(none)", checks=checks, diff=diff)
|
|
87
|
+
payload = {
|
|
88
|
+
"model": agent.settings.model,
|
|
89
|
+
"messages": [*agent.messages, {"role": "user", "content": prompt}],
|
|
90
|
+
"tools": agent.tool_schemas(), # as in the session, so the cached conversation is reused
|
|
91
|
+
"think": agent.settings.think, # without reasoning it missed every gap it caught with it, and wasn't faster
|
|
92
|
+
"format": SCHEMA,
|
|
93
|
+
"keep_alive": agent.settings.keep_alive,
|
|
94
|
+
"options": agent.options(),
|
|
95
|
+
}
|
|
96
|
+
reply = agent.ollama.chat(payload)
|
|
97
|
+
data = parse_json((reply.get("message") or {}).get("content") or "")
|
|
98
|
+
problems = data.get("problems") if isinstance(data.get("problems"), list) else []
|
|
99
|
+
return [str(p).strip()[:500] for p in problems if str(p).strip()][:MAX_PROBLEMS]
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def feedback(problems: list[str]) -> str:
|
|
103
|
+
return FEEDBACK.format(problems="\n".join(f"- {p}" for p in problems))
|
lcode/tools.py
CHANGED
|
@@ -448,6 +448,7 @@ class Toolbox:
|
|
|
448
448
|
self.formats: dict[str, TextFormat] = {} # encoding and line endings of the files read
|
|
449
449
|
self.notes: list[str] = [] # the model's notes on the task (todo_write): decisions, findings, questions
|
|
450
450
|
self.changed: dict[str, None] = {} # files lcode wrote in this session, in order
|
|
451
|
+
self.before: dict[str, str | None] = {} # files changed in this request: their text before (None: new)
|
|
451
452
|
self.todos: list[dict] = []
|
|
452
453
|
# An editor's buffers (lcode acp): read unsaved changes and write through the editor.
|
|
453
454
|
self.reader: Callable[[Path], str | None] | None = None
|
|
@@ -870,6 +871,8 @@ class Toolbox:
|
|
|
870
871
|
p.parent.mkdir(parents=True, exist_ok=True)
|
|
871
872
|
fmt = self.formats.get(str(p)) or (decode(p.read_bytes())[1] if p.exists() else TextFormat())
|
|
872
873
|
data = encode(content, fmt) # before anything is written: it may not be possible
|
|
874
|
+
if self.rel(p) not in self.before:
|
|
875
|
+
self.before[self.rel(p)] = decode(p.read_bytes())[0] if p.exists() else None
|
|
873
876
|
if self.writer is not None:
|
|
874
877
|
self.writer(p, content) # the editor updates its buffer (and the file)
|
|
875
878
|
if not p.exists() or p.read_bytes() != data:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: lcode-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.32.0
|
|
4
4
|
Summary: A local-first terminal coding agent powered by open-weight models on your own GPU or Mac, via Ollama.
|
|
5
5
|
Project-URL: Homepage, https://nasser1941.github.io/lcode/
|
|
6
6
|
Project-URL: Documentation, https://nasser1941.github.io/lcode/
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
lcode/__init__.py,sha256=
|
|
1
|
+
lcode/__init__.py,sha256=WYtKNLgt5PjAq5IrasutTzXxW9RCwY4T0ZQs0OxnnLs,473
|
|
2
2
|
lcode/__main__.py,sha256=s5N5pryX2FAu93GGZ3FxUrIXHWGzxz66lKUoaV_h8Ws,35
|
|
3
3
|
lcode/acp.py,sha256=d97VV3sbqXdWKhPQQNbYRaDTm8WrUk0mGbDLiOyX7jE,29058
|
|
4
4
|
lcode/action.py,sha256=wuT5F9EJCdEligPeytzmEi8FpahWBhXer528tpuTj_k,16711
|
|
5
|
-
lcode/agent.py,sha256=
|
|
6
|
-
lcode/api.py,sha256=
|
|
5
|
+
lcode/agent.py,sha256=ztjxSzYkvUvwuHVEI9piFnuOV8glHBe9ULNIk7x2HKQ,72682
|
|
6
|
+
lcode/api.py,sha256=YTfXVMSYSp1EC3tNI_fW-JcNBgrdFTN7V57HNIzB7Kc,15861
|
|
7
7
|
lcode/backends.py,sha256=dtJHrC6ys73bRDg64z0tQz1PavmeAkiODZu1fOO9ExQ,20635
|
|
8
8
|
lcode/bench.py,sha256=KDgPnkceZOS3gDDEl5j6-k8Ser2es4-IuV_S8p_46Zo,41517
|
|
9
9
|
lcode/bench_backend.py,sha256=X2fo-zRX92Xp3KMxSsFlWioc2vRupBTtowj5kLME8mw,14287
|
|
@@ -11,10 +11,10 @@ lcode/bench_runtime.py,sha256=EjzNgIvUkdbT8cbSy1TpmlyeIk6e-ipjlDFpM7Dnqx0,6835
|
|
|
11
11
|
lcode/catalog.py,sha256=pZ1azX9OH2r4JE2c6E5OfwywpgS39-W2oXzoCHJhmtM,4141
|
|
12
12
|
lcode/checkpoints.py,sha256=eqPtmPe44-aweWqc2H21ROogwzIt3NpvcUobsaCHoGY,18354
|
|
13
13
|
lcode/checks.py,sha256=FOD8DOxPWXY1RMtrL9ONJsOxsV10BLgzPvzIJMK5NrU,6582
|
|
14
|
-
lcode/cli.py,sha256=
|
|
14
|
+
lcode/cli.py,sha256=pB8gnPuVkqanm9amuLKWanH3_0onpn8oS8botxl-DSw,41292
|
|
15
15
|
lcode/clipboard.py,sha256=nTSdJyCXPdtjH947RjvB3QvRqnL5HZsS9KB8EkC42cc,5138
|
|
16
16
|
lcode/codesearch.py,sha256=Io8leN1nb_Y-Dvlm9xaGtwUWYXX-ooswuznJV6dGU1s,10766
|
|
17
|
-
lcode/config.py,sha256=
|
|
17
|
+
lcode/config.py,sha256=CujFZiUPsbZERjPw2j_uTBnZqUfCgYz1hvcvQSSMCu0,11421
|
|
18
18
|
lcode/context.py,sha256=0YYLrC7gI164HqDjW_jrgHSnfrAilrRUoTLhvw54VI8,19082
|
|
19
19
|
lcode/extensions.py,sha256=W0HFDl0BvROzr7i_qtabHdIbacBgP5o5qIJLzoM2oNE,16806
|
|
20
20
|
lcode/frontmatter.py,sha256=Bx0n4vLPhp7ZCWx-g7xqzqNy5VoKBxyeeikh5UFB_gA,2441
|
|
@@ -36,11 +36,12 @@ lcode/repeats.py,sha256=-vcbj363nFcIyso7yFJgsbHz9C6VOu2EOg3Svs4eFyE,4091
|
|
|
36
36
|
lcode/repl.py,sha256=0f3nojURlQE8Pm_JkXvh9y7nEg1CHG3xanZIs0osPxw,52107
|
|
37
37
|
lcode/repomap.py,sha256=1GRJgEUjBl9XHSXsF7tSGXBCEgsY-3CzwMohaTudZ_M,13969
|
|
38
38
|
lcode/residency.py,sha256=bDB2J0SZULDOz6wYuMCnkjacYk7pWi5f75iY83ycAXQ,6912
|
|
39
|
+
lcode/review.py,sha256=0QBIS-R1B2b3zqx5TcC1qZptpKBbrDhYvMKSNCaDAUo,4686
|
|
39
40
|
lcode/sandbox.py,sha256=u_pkrVRXhCGhh-wFDPwuZ3jGG7UeXxXRAeBNsm37ZvE,8608
|
|
40
41
|
lcode/secretscan.py,sha256=6Euvfk2gCtK7lZbuQD84zgWuSECi6OnSw8V5rFu1tfU,13575
|
|
41
42
|
lcode/sessions.py,sha256=wOR-J0EHgJxLSPboKPHnvBcp5VTUYTj3tZWgpsa6-K4,4013
|
|
42
43
|
lcode/subagents.py,sha256=GGn2E7QUwEsShJEHXaMhG53leyGFUZwJku_n33gJguU,29157
|
|
43
|
-
lcode/tools.py,sha256=
|
|
44
|
+
lcode/tools.py,sha256=5qaQISmPqkQiM7i1b1_3lDxbokugGRyGNOmSHOBAFDQ,61426
|
|
44
45
|
lcode/update.py,sha256=i92bnW252VneYh0vD6djxmXsDOa5MXP20bjlLZUue_c,25236
|
|
45
46
|
lcode/vision.py,sha256=w33QPmdGwP33wM4mvmAH4amFDZ1xzeXhEsSLJ-STSHY,4243
|
|
46
47
|
lcode/web.py,sha256=vyxKbSRJTl1Lj3hj7Yd_NwTgbv0Xi6dup2YfUXjqp-Y,14579
|
|
@@ -60,8 +61,8 @@ lcode/servers/__init__.py,sha256=qrIhxEodEB8cjKEQ4Cicc0GsQhE2OH-9qlVHzr3-tq8,77
|
|
|
60
61
|
lcode/servers/encord.py,sha256=WSauawL1UKYZCUAG1oalcKL_An3DVof-JM6xIgFyQSE,12769
|
|
61
62
|
lcode/servers/valohai.py,sha256=e5xZGIoa4cja4f5i85q1GpL9c7cglUjV8jN2co1CFMY,14430
|
|
62
63
|
lcode/servers/xai.py,sha256=h2emAvHSnkuB9WmJInlynsDhvxJwNVD2AHFX7vqMXNc,13627
|
|
63
|
-
lcode_cli-0.
|
|
64
|
-
lcode_cli-0.
|
|
65
|
-
lcode_cli-0.
|
|
66
|
-
lcode_cli-0.
|
|
67
|
-
lcode_cli-0.
|
|
64
|
+
lcode_cli-0.32.0.dist-info/METADATA,sha256=QWfst181FXU5mfBDoHdf_9FpIj_SJvVAkbSdvNNv5lo,12620
|
|
65
|
+
lcode_cli-0.32.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
66
|
+
lcode_cli-0.32.0.dist-info/entry_points.txt,sha256=Hxsn_itbnbgft3U0FwxWdmEt0yoAV2LB-nJDnL9WT20,172
|
|
67
|
+
lcode_cli-0.32.0.dist-info/licenses/LICENSE,sha256=JWjmoL7nNIC1XUa-dZm2hwLUgjUQMFo6k8APb0idNzs,1074
|
|
68
|
+
lcode_cli-0.32.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|