lcode-cli 0.26.0__py3-none-any.whl → 0.27.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 +37 -7
- lcode/api.py +1 -0
- lcode/cli.py +15 -0
- lcode/config.py +16 -0
- lcode/context.py +81 -4
- lcode/repl.py +2 -1
- {lcode_cli-0.26.0.dist-info → lcode_cli-0.27.0.dist-info}/METADATA +1 -1
- {lcode_cli-0.26.0.dist-info → lcode_cli-0.27.0.dist-info}/RECORD +12 -12
- {lcode_cli-0.26.0.dist-info → lcode_cli-0.27.0.dist-info}/WHEEL +0 -0
- {lcode_cli-0.26.0.dist-info → lcode_cli-0.27.0.dist-info}/entry_points.txt +0 -0
- {lcode_cli-0.26.0.dist-info → lcode_cli-0.27.0.dist-info}/licenses/LICENSE +0 -0
lcode/__init__.py
CHANGED
lcode/agent.py
CHANGED
|
@@ -234,6 +234,7 @@ class Settings:
|
|
|
234
234
|
notify_after: int = 30 # seconds: a request this long notifies when it's done or waits for an answer
|
|
235
235
|
max_parallel_agents: int = 1
|
|
236
236
|
secret_check: bool = True # scan what git commit and git push would add (lcode.secretscan)
|
|
237
|
+
compact_at: int = 0 # tokens: make room at this size even when the window is larger (0: only at 85%)
|
|
237
238
|
repeat_limit: int = 3 # identical calls with identical results before the model is told (lcode.repeats)
|
|
238
239
|
|
|
239
240
|
|
|
@@ -270,6 +271,7 @@ class Agent:
|
|
|
270
271
|
self.agent_runs: list[subagents.Record] = [] # subagents run in this session, for /agents
|
|
271
272
|
self.plan = "" # the plan the user approved; kept through compaction
|
|
272
273
|
self.pruned = self.compacted = 0 # how often the context was pruned or summarized automatically
|
|
274
|
+
self.summarized_size = 0 # tokens right after the last summary (0: none in this conversation)
|
|
273
275
|
self._extensions: tuple[Path, extensions.Extensions] | None = None
|
|
274
276
|
self.skills_loaded: set[str] = set() # skills whose instructions are in the conversation
|
|
275
277
|
# Set on subagents (see lcode.subagents):
|
|
@@ -514,6 +516,7 @@ class Agent:
|
|
|
514
516
|
return WEB_PROMPT.format(tools=tools, date=dt.date.today().isoformat())
|
|
515
517
|
|
|
516
518
|
def reset(self) -> None:
|
|
519
|
+
self.summarized_size = 0
|
|
517
520
|
self.messages = [{"role": "system", "content": self.system_prompt()}]
|
|
518
521
|
self._mcp_prompt = ""
|
|
519
522
|
self.tools.read_mtimes.clear()
|
|
@@ -1046,13 +1049,27 @@ class Agent:
|
|
|
1046
1049
|
return text + ("\n\n" + "\n\n".join(attached) if attached else "")
|
|
1047
1050
|
|
|
1048
1051
|
# -- context management
|
|
1052
|
+
def compact_limit(self) -> int:
|
|
1053
|
+
"""The tokens in use at which lcode makes room: 85% of the window, or `compact_at` when that's lower.
|
|
1054
|
+
Small models lose track in long contexts well before a large window is full."""
|
|
1055
|
+
limit = int(AUTO_COMPACT_RATIO * self.settings.context)
|
|
1056
|
+
if self.settings.compact_at > 0:
|
|
1057
|
+
limit = min(limit, self.settings.compact_at)
|
|
1058
|
+
return limit
|
|
1059
|
+
|
|
1049
1060
|
def maybe_compact(self) -> None:
|
|
1050
|
-
|
|
1061
|
+
limit = self.compact_limit()
|
|
1062
|
+
if self.ctx_used <= limit:
|
|
1051
1063
|
return
|
|
1064
|
+
enough = int(limit * PRUNED_ENOUGH / AUTO_COMPACT_RATIO) # after pruning, a summary isn't needed below this
|
|
1052
1065
|
if self.settings.prune:
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1066
|
+
removed: list[str] = [] # files and pages whose only copy goes
|
|
1067
|
+
saved = context_tools.prune(self.messages, removed=removed) # tool output from before the last two requests
|
|
1068
|
+
if self.ctx_used - saved // 3 > enough:
|
|
1069
|
+
saved += context_tools.prune(
|
|
1070
|
+
self.messages, keep=1, removed=removed
|
|
1071
|
+
) # not enough: before the last request
|
|
1072
|
+
context_tools.note_removed(self.messages, removed)
|
|
1056
1073
|
if saved:
|
|
1057
1074
|
self.pruned += 1
|
|
1058
1075
|
self.ctx_used = max(len(self.messages[0]["content"]) // 3, self.ctx_used - saved // 3)
|
|
@@ -1060,9 +1077,17 @@ class Agent:
|
|
|
1060
1077
|
f"[dim]Removed old tool output from the conversation (~{format_tokens(saved // 3)} tokens) to "
|
|
1061
1078
|
"make room.[/]"
|
|
1062
1079
|
)
|
|
1063
|
-
if self.ctx_used <=
|
|
1080
|
+
if self.ctx_used <= enough:
|
|
1064
1081
|
return
|
|
1065
|
-
self.
|
|
1082
|
+
window_full = self.ctx_used > AUTO_COMPACT_RATIO * self.settings.context
|
|
1083
|
+
if not window_full and self.summarized_size and self.ctx_used - self.summarized_size < limit // 4:
|
|
1084
|
+
return # summarized not long ago: summarizing again so soon would only lose more
|
|
1085
|
+
if limit < AUTO_COMPACT_RATIO * self.settings.context:
|
|
1086
|
+
self.console.print(
|
|
1087
|
+
f"[yellow]The conversation reached {format_tokens(limit)} tokens (compact_at) — summarizing it…[/]"
|
|
1088
|
+
)
|
|
1089
|
+
else:
|
|
1090
|
+
self.console.print("[yellow]Context is nearly full — compacting the conversation…[/]")
|
|
1066
1091
|
self.compacted += 1
|
|
1067
1092
|
self.compact()
|
|
1068
1093
|
|
|
@@ -1083,9 +1108,13 @@ class Agent:
|
|
|
1083
1108
|
with self.console.status("[cyan]Compacting…[/]"):
|
|
1084
1109
|
for chunk in self.chat([*self.messages, {"role": "user", "content": instructions}], None, False):
|
|
1085
1110
|
summary += chunk.get("message", {}).get("content", "")
|
|
1111
|
+
requests = context_tools.user_requests(self.messages)
|
|
1086
1112
|
self.messages = [
|
|
1087
1113
|
{"role": "system", "content": self.system_prompt()},
|
|
1088
|
-
{
|
|
1114
|
+
{
|
|
1115
|
+
"role": "user",
|
|
1116
|
+
"content": f"{sessions.SUMMARY_PREFIX}\n\n{summary}" + context_tools.requests_block(requests),
|
|
1117
|
+
},
|
|
1089
1118
|
{"role": "assistant", "content": "Got it — I have the context from the summary and will continue."},
|
|
1090
1119
|
]
|
|
1091
1120
|
if self.plan: # the approved plan stays word for word
|
|
@@ -1097,6 +1126,7 @@ class Agent:
|
|
|
1097
1126
|
)
|
|
1098
1127
|
self.skills_loaded.clear()
|
|
1099
1128
|
self.ctx_used = sum(len(m["content"]) for m in self.messages) // 3
|
|
1129
|
+
self.summarized_size = self.ctx_used
|
|
1100
1130
|
self.reflected = len(self.messages)
|
|
1101
1131
|
self.console.print(Panel(Markdown(summary), title="Compacted summary", border_style="blue"))
|
|
1102
1132
|
|
lcode/api.py
CHANGED
|
@@ -196,6 +196,7 @@ def open_agent(cwd: Path, options: Options, console: Console, hw: Hardware | Non
|
|
|
196
196
|
notify_after=cfg["notify_after"],
|
|
197
197
|
secret_check=cfg["secret_check"],
|
|
198
198
|
repeat_limit=cfg["repeat_limit"],
|
|
199
|
+
compact_at=cfg["compact_at"],
|
|
199
200
|
)
|
|
200
201
|
agent = Agent(ollama, settings, cwd, console=console)
|
|
201
202
|
agent.interactive = options.interactive
|
lcode/cli.py
CHANGED
|
@@ -579,6 +579,7 @@ def cmd_bench(args) -> None:
|
|
|
579
579
|
web="off",
|
|
580
580
|
checkpoints=False,
|
|
581
581
|
prune=not args.no_prune,
|
|
582
|
+
compact_at=cfg["compact_at"] if args.compact_at is None else args.compact_at,
|
|
582
583
|
repo_map=args.repo_map,
|
|
583
584
|
embed_model=cfg["embed_model"] if args.code_search else "off",
|
|
584
585
|
)
|
|
@@ -678,6 +679,14 @@ def cmd_chat(args) -> None:
|
|
|
678
679
|
sys.exit(exit_code)
|
|
679
680
|
|
|
680
681
|
|
|
682
|
+
def compact_tokens(value: str) -> int:
|
|
683
|
+
"""`--compact-at`: a token count such as 64k, or 0."""
|
|
684
|
+
try:
|
|
685
|
+
return config.parse_compact_at(value)
|
|
686
|
+
except ConfigError as e:
|
|
687
|
+
raise argparse.ArgumentTypeError(str(e)) from e
|
|
688
|
+
|
|
689
|
+
|
|
681
690
|
def build_parser() -> argparse.ArgumentParser:
|
|
682
691
|
parser = argparse.ArgumentParser(
|
|
683
692
|
prog="lcode",
|
|
@@ -765,6 +774,12 @@ def build_subparsers() -> dict[str, argparse.ArgumentParser]:
|
|
|
765
774
|
p.add_argument("--repo-map", action="store_true", help="give the model the repository map (off by default)")
|
|
766
775
|
p.add_argument("--code-search", action="store_true", help="index each task's folder and offer semantic code search")
|
|
767
776
|
p.add_argument("--no-prune", action="store_true", help="don't remove old tool output (to compare, with --session)")
|
|
777
|
+
p.add_argument(
|
|
778
|
+
"--compact-at",
|
|
779
|
+
type=compact_tokens,
|
|
780
|
+
metavar="TOKENS",
|
|
781
|
+
help="summarize at this many tokens, e.g. 64k (default: the compact_at setting; 0: only at 85%%)",
|
|
782
|
+
)
|
|
768
783
|
subs["bench"] = p
|
|
769
784
|
p = argparse.ArgumentParser(
|
|
770
785
|
prog="lcode index",
|
lcode/config.py
CHANGED
|
@@ -61,6 +61,7 @@ SETTINGS: dict[str, tuple[object, type, str]] = {
|
|
|
61
61
|
"notify_after": (30, int, "seconds a request runs before it notifies (with notify on)"),
|
|
62
62
|
"repeat_limit": (3, int, "identical tool calls with identical results before lcode steps in (0: never)"),
|
|
63
63
|
"secret_check": (True, bool, "before git commit and git push, look for passwords, keys and tokens they'd add"),
|
|
64
|
+
"compact_at": (65536, int, "summarize at this many tokens even when the window is larger (0: only at 85%)"),
|
|
64
65
|
"max_parallel_agents": (1, int, "subagents that may run at the same time (more needs OLLAMA_NUM_PARALLEL)"),
|
|
65
66
|
}
|
|
66
67
|
ENV_OVERRIDES = {
|
|
@@ -81,6 +82,19 @@ class ConfigError(ValueError):
|
|
|
81
82
|
pass
|
|
82
83
|
|
|
83
84
|
|
|
85
|
+
MIN_COMPACT_AT = 16384 # below this, the system prompt and a summary alone come close to the ceiling
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def parse_compact_at(value: str | int) -> int:
|
|
89
|
+
"""compact_at: a token count like parse_context's, at least 16K, or 0 (off)."""
|
|
90
|
+
if str(value).strip().lower() in ("0", "off", "false", "none"):
|
|
91
|
+
return 0
|
|
92
|
+
tokens = parse_context(value)
|
|
93
|
+
if tokens < MIN_COMPACT_AT:
|
|
94
|
+
raise ConfigError(f"compact_at {tokens} is too small: use at least 16k, or 0 to turn it off")
|
|
95
|
+
return tokens
|
|
96
|
+
|
|
97
|
+
|
|
84
98
|
def parse_context(value: str | int) -> int:
|
|
85
99
|
"""Parse '131072', '128k', '128K' or '1m' into a token count (k = 1024)."""
|
|
86
100
|
if isinstance(value, int):
|
|
@@ -118,6 +132,8 @@ def coerce(key: str, value: object) -> object:
|
|
|
118
132
|
_, typ, _ = SETTINGS[key]
|
|
119
133
|
if key == "context":
|
|
120
134
|
return parse_context(value) # type: ignore[arg-type]
|
|
135
|
+
if key == "compact_at":
|
|
136
|
+
return parse_compact_at(value) # type: ignore[arg-type]
|
|
121
137
|
if key in ("ollama_host", "searxng_url"):
|
|
122
138
|
return normalize_host(str(value))
|
|
123
139
|
if key == "base_url":
|
lcode/context.py
CHANGED
|
@@ -29,6 +29,10 @@ if TYPE_CHECKING:
|
|
|
29
29
|
KEEP_RECENT_REQUESTS = 2 # tool results of the last requests stay as they are
|
|
30
30
|
MIN_PRUNE_CHARS = 400 # shorter results aren't worth replacing
|
|
31
31
|
PRUNED = "[lcode: " # how stubs start, so they're never pruned twice
|
|
32
|
+
GONE = ( # a removed file read: firm, because models answer from the stub instead of reading it again
|
|
33
|
+
"earlier; its content was removed to save context and isn't in this conversation any more. Read it again "
|
|
34
|
+
"before answering anything about it.]"
|
|
35
|
+
)
|
|
32
36
|
KEEP_TOOLS = {"agent", "skill", "memory", "todo_write", "present_plan"} # short, or still guiding the work
|
|
33
37
|
ERROR_LINE = re.compile(
|
|
34
38
|
r"error|exception|traceback|failed|failure|fatal|panic|assert|denied|not found|cannot|can't|undefined", re.I
|
|
@@ -37,6 +41,56 @@ MAX_ERROR_LINES = 40
|
|
|
37
41
|
OUTPUT_DAYS = 7 # saved full outputs are deleted after this
|
|
38
42
|
|
|
39
43
|
|
|
44
|
+
# ----------------------------------------------------------------------------- the user's requests
|
|
45
|
+
|
|
46
|
+
REQUESTS_HEADER = "[The user's requests in this conversation, word for word, oldest first]"
|
|
47
|
+
MAX_REQUESTS = 8 # the most recent ones are kept through a summary
|
|
48
|
+
MAX_REQUEST_CHARS = 1500
|
|
49
|
+
# What lcode appends to the user's words: attached files, images and folders, and its own notes.
|
|
50
|
+
ATTACHED = re.compile(r"\n\n(?:<file path=|<image path=|<directory path=|\[lcode[:\]] |\[The user wants the )")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def request_text(content: str) -> str:
|
|
54
|
+
"""The user's own words in a message, without what lcode attached to it."""
|
|
55
|
+
cut = ATTACHED.search(content)
|
|
56
|
+
return (content[: cut.start()] if cut else content).strip()
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def user_requests(messages: list[dict]) -> list[str]:
|
|
60
|
+
"""What the user asked in the conversation, oldest first, including the requests an earlier summary kept."""
|
|
61
|
+
requests: list[str] = []
|
|
62
|
+
for message in messages:
|
|
63
|
+
content = message.get("content") or ""
|
|
64
|
+
if message.get("role") != "user":
|
|
65
|
+
continue
|
|
66
|
+
if content.startswith(SUMMARY_PREFIX):
|
|
67
|
+
start = content.find(REQUESTS_HEADER)
|
|
68
|
+
if start >= 0:
|
|
69
|
+
rest = content[start + len(REQUESTS_HEADER) :]
|
|
70
|
+
try:
|
|
71
|
+
kept, _ = json.JSONDecoder().raw_decode(rest[rest.index("[") :])
|
|
72
|
+
requests += [str(r) for r in kept]
|
|
73
|
+
except ValueError:
|
|
74
|
+
pass
|
|
75
|
+
continue
|
|
76
|
+
if content.startswith("[lcode]"):
|
|
77
|
+
continue # lcode's own nudges
|
|
78
|
+
text = request_text(content)
|
|
79
|
+
if text:
|
|
80
|
+
requests.append(text)
|
|
81
|
+
return requests
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def requests_block(requests: list[str]) -> str:
|
|
85
|
+
"""The user's latest requests, word for word, to keep the goal through a summary."""
|
|
86
|
+
if not requests:
|
|
87
|
+
return ""
|
|
88
|
+
kept = [r if len(r) <= MAX_REQUEST_CHARS else f"{r[: MAX_REQUEST_CHARS - 200]} […] {r[-150:]}" for r in requests]
|
|
89
|
+
older = len(kept) - MAX_REQUESTS
|
|
90
|
+
note = f" (and {older} earlier, in the summary)" if older > 0 else ""
|
|
91
|
+
return f"\n\n{REQUESTS_HEADER}{note}\n{json.dumps(kept[-MAX_REQUESTS:], ensure_ascii=False, indent=1)}"
|
|
92
|
+
|
|
93
|
+
|
|
40
94
|
# ----------------------------------------------------------------------------- pruning
|
|
41
95
|
|
|
42
96
|
|
|
@@ -63,7 +117,7 @@ def stub(name: str, args: dict, content: str) -> str:
|
|
|
63
117
|
if args.get("offset") or args.get("limit"):
|
|
64
118
|
start = int(args.get("offset") or 1)
|
|
65
119
|
span = f" from line {start}"
|
|
66
|
-
return f"{PRUNED}read {args.get('path', 'a file')}{span}
|
|
120
|
+
return f"{PRUNED}read {args.get('path', 'a file')}{span} {GONE}"
|
|
67
121
|
if name == "bash":
|
|
68
122
|
command = " ".join(str(args.get("command", "")).split())
|
|
69
123
|
command = command if len(command) <= 80 else command[:79] + "…"
|
|
@@ -92,8 +146,9 @@ def boundary(messages: list[dict], keep: int = KEEP_RECENT_REQUESTS) -> int:
|
|
|
92
146
|
return requests[-keep] if len(requests) >= keep else 0
|
|
93
147
|
|
|
94
148
|
|
|
95
|
-
def prune(messages: list[dict], keep: int = KEEP_RECENT_REQUESTS) -> int:
|
|
96
|
-
"""Replace stale tool results with stubs, in place. Returns the number of characters saved
|
|
149
|
+
def prune(messages: list[dict], keep: int = KEEP_RECENT_REQUESTS, removed: list[str] | None = None) -> int:
|
|
150
|
+
"""Replace stale tool results with stubs, in place. Returns the number of characters saved; the files and
|
|
151
|
+
pages whose only copy went are added to `removed`."""
|
|
97
152
|
calls = calls_for_results(messages)
|
|
98
153
|
edge = boundary(messages, keep)
|
|
99
154
|
# A read is superseded by a later read of the whole file, or of the same lines: not by a later
|
|
@@ -118,12 +173,34 @@ def prune(messages: list[dict], keep: int = KEEP_RECENT_REQUESTS) -> int:
|
|
|
118
173
|
continue
|
|
119
174
|
new = stub(name, args, content)
|
|
120
175
|
if reread:
|
|
121
|
-
new = new.replace(
|
|
176
|
+
new = new.replace(
|
|
177
|
+
GONE, "earlier (read again later); removed to save context. Read it again if you need it.]"
|
|
178
|
+
)
|
|
179
|
+
elif removed is not None and name in ("read_file", "web_fetch"):
|
|
180
|
+
what = str(args.get("path") or args.get("url") or "")
|
|
181
|
+
if what and what not in removed:
|
|
182
|
+
removed.append(what)
|
|
122
183
|
messages[i]["content"] = new
|
|
123
184
|
saved += len(content) - len(new)
|
|
124
185
|
return saved
|
|
125
186
|
|
|
126
187
|
|
|
188
|
+
def note_removed(messages: list[dict], removed: list[str]) -> None:
|
|
189
|
+
"""Tell the model, next to the request it's working on, which files it no longer has: a stub deep in the
|
|
190
|
+
conversation is easy to overlook, and models then answer from memory instead of reading again."""
|
|
191
|
+
if not removed:
|
|
192
|
+
return
|
|
193
|
+
for message in reversed(messages):
|
|
194
|
+
content = str(message.get("content", ""))
|
|
195
|
+
if message.get("role") == "user" and not content.startswith(("[lcode]", SUMMARY_PREFIX)):
|
|
196
|
+
names = ", ".join(removed[:10]) + (f" and {len(removed) - 10} more" if len(removed) > 10 else "")
|
|
197
|
+
message["content"] = (
|
|
198
|
+
f"{content}\n\n[lcode] To make room, lcode removed what you read earlier from: {names}. It isn't in "
|
|
199
|
+
"this conversation any more: read it again before answering anything about it, don't answer from memory."
|
|
200
|
+
)
|
|
201
|
+
return
|
|
202
|
+
|
|
203
|
+
|
|
127
204
|
# ----------------------------------------------------------------------------- long output
|
|
128
205
|
|
|
129
206
|
|
lcode/repl.py
CHANGED
|
@@ -242,7 +242,8 @@ def context_command(agent: Agent, arg: str, hardware: Hardware) -> None:
|
|
|
242
242
|
c.print(
|
|
243
243
|
f"In use: {format_tokens(agent.ctx_used)} of {format_tokens(s.context)} tokens "
|
|
244
244
|
f"({100 * agent.ctx_used / s.context:.0f}%) in {len(agent.messages)} message"
|
|
245
|
-
f"{'' if len(agent.messages) == 1 else 's'};
|
|
245
|
+
f"{'' if len(agent.messages) == 1 else 's'}; makes room at {format_tokens(agent.compact_limit())} "
|
|
246
|
+
+ ("(compact_at)." if agent.compact_limit() < AUTO_COMPACT_RATIO * s.context else "(85%).")
|
|
246
247
|
)
|
|
247
248
|
if agent.mcp and agent.mcp.ready():
|
|
248
249
|
how = "found on demand" if agent.mcp.searching(s.context) else "sent with every request"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: lcode-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.27.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,20 +1,20 @@
|
|
|
1
|
-
lcode/__init__.py,sha256=
|
|
1
|
+
lcode/__init__.py,sha256=JUcNjfBPUQX6hKCFSklgC04DhC6xrDnysFFhCU7p5Xc,473
|
|
2
2
|
lcode/__main__.py,sha256=s5N5pryX2FAu93GGZ3FxUrIXHWGzxz66lKUoaV_h8Ws,35
|
|
3
3
|
lcode/acp.py,sha256=Tpc8lsvffZSYbTRI4t7X4E2chahqZIPcKeYIcL5bV3Y,29035
|
|
4
4
|
lcode/action.py,sha256=wuT5F9EJCdEligPeytzmEi8FpahWBhXer528tpuTj_k,16711
|
|
5
|
-
lcode/agent.py,sha256=
|
|
6
|
-
lcode/api.py,sha256=
|
|
5
|
+
lcode/agent.py,sha256=tGNjbs8cw2X7IUBb70juI3JH5IpXmmIXOcteTsMhOtA,57936
|
|
6
|
+
lcode/api.py,sha256=aqWnGCy1jNuIktJEHo9ncbHNTXn2QO3BoNiggyo9ZmQ,15456
|
|
7
7
|
lcode/backends.py,sha256=dtJHrC6ys73bRDg64z0tQz1PavmeAkiODZu1fOO9ExQ,20635
|
|
8
8
|
lcode/bench.py,sha256=7ICipu_2GXW6vE519XeZucc2GSWA44votT8JvqcNv1k,40964
|
|
9
9
|
lcode/bench_backend.py,sha256=X2fo-zRX92Xp3KMxSsFlWioc2vRupBTtowj5kLME8mw,14287
|
|
10
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
|
-
lcode/cli.py,sha256=
|
|
13
|
+
lcode/cli.py,sha256=M6Mjd5BROSGlZj4J6TrSZMJqI-OVfUEWPoC0TQyOQ28,40831
|
|
14
14
|
lcode/clipboard.py,sha256=nTSdJyCXPdtjH947RjvB3QvRqnL5HZsS9KB8EkC42cc,5138
|
|
15
15
|
lcode/codesearch.py,sha256=Io8leN1nb_Y-Dvlm9xaGtwUWYXX-ooswuznJV6dGU1s,10766
|
|
16
|
-
lcode/config.py,sha256=
|
|
17
|
-
lcode/context.py,sha256=
|
|
16
|
+
lcode/config.py,sha256=q1zGzH3p5U23ai6O9Jai3dS-s30CuQ9gc5cWX0_yxWE,11195
|
|
17
|
+
lcode/context.py,sha256=_f0NbXyjA4SyH2RCr49AiWwtAfr_PVDaqyFQ5fZDhkg,14404
|
|
18
18
|
lcode/extensions.py,sha256=W0HFDl0BvROzr7i_qtabHdIbacBgP5o5qIJLzoM2oNE,16806
|
|
19
19
|
lcode/frontmatter.py,sha256=Bx0n4vLPhp7ZCWx-g7xqzqNy5VoKBxyeeikh5UFB_gA,2441
|
|
20
20
|
lcode/gitflow.py,sha256=6j_nnCBZXkX1qhTI7K4CyZ5D0NAZLpH96weFEo64AkQ,27913
|
|
@@ -31,7 +31,7 @@ lcode/permissions.py,sha256=i04YLtqYCxwApgawomPp4d35uk9HAJtpKY__gfw8j9s,6347
|
|
|
31
31
|
lcode/planning.py,sha256=Q2upaoZPnXDMQT2F-ETxX1lk_wDntTzhSKNVYIQSoQA,6540
|
|
32
32
|
lcode/render.py,sha256=gMvf4W3qkLUJ4Vot3az_hP_zRDAItJC9pP-68dHFkfA,1375
|
|
33
33
|
lcode/repeats.py,sha256=uzyAewX03nJf5dKwYFH4y9ZDnh0Lvy2k0qC2vdntM5Y,4061
|
|
34
|
-
lcode/repl.py,sha256=
|
|
34
|
+
lcode/repl.py,sha256=Y53tTvdoTP6CZOtq96CzbvPcwVlYNc9fppMV0hAlRSY,49573
|
|
35
35
|
lcode/repomap.py,sha256=1GRJgEUjBl9XHSXsF7tSGXBCEgsY-3CzwMohaTudZ_M,13969
|
|
36
36
|
lcode/sandbox.py,sha256=u_pkrVRXhCGhh-wFDPwuZ3jGG7UeXxXRAeBNsm37ZvE,8608
|
|
37
37
|
lcode/secretscan.py,sha256=6Euvfk2gCtK7lZbuQD84zgWuSECi6OnSw8V5rFu1tfU,13575
|
|
@@ -57,8 +57,8 @@ lcode/servers/__init__.py,sha256=qrIhxEodEB8cjKEQ4Cicc0GsQhE2OH-9qlVHzr3-tq8,77
|
|
|
57
57
|
lcode/servers/encord.py,sha256=WSauawL1UKYZCUAG1oalcKL_An3DVof-JM6xIgFyQSE,12769
|
|
58
58
|
lcode/servers/valohai.py,sha256=e5xZGIoa4cja4f5i85q1GpL9c7cglUjV8jN2co1CFMY,14430
|
|
59
59
|
lcode/servers/xai.py,sha256=h2emAvHSnkuB9WmJInlynsDhvxJwNVD2AHFX7vqMXNc,13627
|
|
60
|
-
lcode_cli-0.
|
|
61
|
-
lcode_cli-0.
|
|
62
|
-
lcode_cli-0.
|
|
63
|
-
lcode_cli-0.
|
|
64
|
-
lcode_cli-0.
|
|
60
|
+
lcode_cli-0.27.0.dist-info/METADATA,sha256=pASpYtQ_MeN-50aD2sdpTfxMKuX2Tz00LaJa2pT1DmM,12620
|
|
61
|
+
lcode_cli-0.27.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
62
|
+
lcode_cli-0.27.0.dist-info/entry_points.txt,sha256=Hxsn_itbnbgft3U0FwxWdmEt0yoAV2LB-nJDnL9WT20,172
|
|
63
|
+
lcode_cli-0.27.0.dist-info/licenses/LICENSE,sha256=JWjmoL7nNIC1XUa-dZm2hwLUgjUQMFo6k8APb0idNzs,1074
|
|
64
|
+
lcode_cli-0.27.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|