1bcoder 0.1.8__tar.gz → 0.1.9__tar.gz

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.
Files changed (101) hide show
  1. {1bcoder-0.1.8 → 1bcoder-0.1.9}/1bcoder.egg-info/PKG-INFO +1 -1
  2. {1bcoder-0.1.8 → 1bcoder-0.1.9}/PKG-INFO +1 -1
  3. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/aliases.txt +4 -0
  4. {1bcoder-0.1.8 → 1bcoder-0.1.9}/chat.py +66 -3
  5. {1bcoder-0.1.8 → 1bcoder-0.1.9}/pyproject.toml +1 -1
  6. {1bcoder-0.1.8 → 1bcoder-0.1.9}/1bcoder.egg-info/SOURCES.txt +0 -0
  7. {1bcoder-0.1.8 → 1bcoder-0.1.9}/1bcoder.egg-info/dependency_links.txt +0 -0
  8. {1bcoder-0.1.8 → 1bcoder-0.1.9}/1bcoder.egg-info/entry_points.txt +0 -0
  9. {1bcoder-0.1.8 → 1bcoder-0.1.9}/1bcoder.egg-info/requires.txt +0 -0
  10. {1bcoder-0.1.8 → 1bcoder-0.1.9}/1bcoder.egg-info/top_level.txt +0 -0
  11. {1bcoder-0.1.8 → 1bcoder-0.1.9}/LICENSE +0 -0
  12. {1bcoder-0.1.8 → 1bcoder-0.1.9}/README.md +0 -0
  13. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/__init__.py +0 -0
  14. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/agents/advance.txt +0 -0
  15. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/agents/ask.txt +0 -0
  16. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/agents/compact.txt +0 -0
  17. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/agents/concepts.txt +0 -0
  18. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/agents/fill.txt +0 -0
  19. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/agents/planning.txt +0 -0
  20. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/agents/scan.txt +0 -0
  21. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/agents/sqlite.txt +0 -0
  22. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/agents/websearch.txt +0 -0
  23. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/doc/FLOWS.md +0 -0
  24. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/doc/MCP.md +0 -0
  25. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/doc/OLLAMA_SERVER_PARAM.md +0 -0
  26. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/doc/PARAM.md +0 -0
  27. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/doc/PROC.md +0 -0
  28. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/doc/TRANSLATE.md +0 -0
  29. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/flows/__pycache__/commit_message.cpython-311.pyc +0 -0
  30. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/flows/commit_message.py +0 -0
  31. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/flows/grounding.py +0 -0
  32. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/flows/py_error_trace.py +0 -0
  33. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/flows/simargl_files.py +0 -0
  34. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/flows/webask.py +0 -0
  35. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/map.txt +0 -0
  36. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/proc/action-required.py +0 -0
  37. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/proc/add-save.py +0 -0
  38. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/proc/assist.py +0 -0
  39. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/proc/collect-files.py +0 -0
  40. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/proc/ctx_cut.py +0 -0
  41. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/proc/extract-code.py +0 -0
  42. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/proc/extract-files.py +0 -0
  43. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/proc/extract-list.py +0 -0
  44. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/proc/grounding-check.py +0 -0
  45. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/proc/md.py +0 -0
  46. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/proc/mdx.py +0 -0
  47. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/proc/pattern-gate.py +0 -0
  48. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/proc/regexp-extract.py +0 -0
  49. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/proc/rude_words.py +0 -0
  50. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/proc/scan-save.py +0 -0
  51. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/proc/secret_check.py +0 -0
  52. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/proc/sql_readonly_guard.py +0 -0
  53. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/proc/tempctx-cut.py +0 -0
  54. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/profiles.txt +0 -0
  55. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/prompts/analysis.txt +0 -0
  56. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/prompts/sumarise.txt +0 -0
  57. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/prompts.txt +0 -0
  58. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/AddFunction.txt +0 -0
  59. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/AskProject.txt +0 -0
  60. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/CheckRequirements.txt +0 -0
  61. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/DockerMySQL.txt +0 -0
  62. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/DockerNginx.txt +0 -0
  63. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/DockerPython.txt +0 -0
  64. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/DockerStack.txt +0 -0
  65. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/DuckDuckGoInstant.txt +0 -0
  66. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/EnvTemplate.txt +0 -0
  67. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/Explain.txt +0 -0
  68. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/ExploreProjectStructure.txt +0 -0
  69. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/GitIgnorePython.txt +0 -0
  70. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/MySQLDump.txt +0 -0
  71. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/NewScript.txt +0 -0
  72. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/PipFreeze.txt +0 -0
  73. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/PyPI.txt +0 -0
  74. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/Refactor.txt +0 -0
  75. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/RunAndFix.txt +0 -0
  76. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/SQLiteSchema.txt +0 -0
  77. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/Translate.txt +0 -0
  78. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/WikiPage.txt +0 -0
  79. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/WikiSearch.txt +0 -0
  80. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/auto-bkup.txt +0 -0
  81. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/edit-control.txt +0 -0
  82. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/parallel_call.txt +0 -0
  83. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/personal/content/create-regular-content.txt +0 -0
  84. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/personal/content/plan.txt +0 -0
  85. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/personal/test/collect-data-from-test-environment.txt +0 -0
  86. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/plan.txt +0 -0
  87. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/remote/create-content-on-remote-server.txt +0 -0
  88. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/set_ctx.txt +0 -0
  89. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/simargl-cli_index_files.txt +0 -0
  90. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/simargl-cli_index_units.txt +0 -0
  91. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/simargl-cli_search.txt +0 -0
  92. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/team-map-worker.txt +0 -0
  93. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/team-search-worker.txt +0 -0
  94. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/team-summarize.txt +0 -0
  95. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/team-tree-worker.txt +0 -0
  96. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/scripts/test.txt +0 -0
  97. {1bcoder-0.1.8 → 1bcoder-0.1.9}/_bcoder_data/teams/code-analysis.yaml +0 -0
  98. {1bcoder-0.1.8 → 1bcoder-0.1.9}/map_index.py +0 -0
  99. {1bcoder-0.1.8 → 1bcoder-0.1.9}/map_query.py +0 -0
  100. {1bcoder-0.1.8 → 1bcoder-0.1.9}/setup.cfg +0 -0
  101. {1bcoder-0.1.8 → 1bcoder-0.1.9}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: 1bcoder
3
- Version: 0.1.8
3
+ Version: 0.1.9
4
4
  Summary: AI coding assistant agent for 1B–7B local models (Ollama, LMStudio, llama.cpp). Terminal REPL with file editing, project map, agents, scripts, and parallel multi-model queries.
5
5
  Project-URL: Homepage, https://github.com/szholobetsky/1bcoder
6
6
  Project-URL: Repository, https://github.com/szholobetsky/1bcoder
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: 1bcoder
3
- Version: 0.1.8
3
+ Version: 0.1.9
4
4
  Summary: AI coding assistant agent for 1B–7B local models (Ollama, LMStudio, llama.cpp). Terminal REPL with file editing, project map, agents, scripts, and parallel multi-model queries.
5
5
  Project-URL: Homepage, https://github.com/szholobetsky/1bcoder
6
6
  Project-URL: Repository, https://github.com/szholobetsky/1bcoder
@@ -11,6 +11,10 @@
11
11
  /compact = /agent compact {{args}}
12
12
  /websearch = /agent websearch {{args}}
13
13
  /webask = /flow webask {{args}}
14
+ /simargl = /run simargl {{args}}
15
+ /sim = /run simargl {{args}}
16
+ /svitovyd = /run svitovyd {{args}}
17
+ /svi = /run svitovyd {{args}}
14
18
 
15
19
  /small = /parallel {{args}} profile: small
16
20
  /explain = /parallel {{args}} profile: explain
@@ -2243,6 +2243,30 @@ class CoderCLI:
2243
2243
  right = right[:5]
2244
2244
  return f"{left}:{right}" if right else left
2245
2245
 
2246
+ def _autosave_prompt(self) -> None:
2247
+ """Ask user whether to save context; save to .1bcoder/autosave/ if confirmed."""
2248
+ if not self.messages:
2249
+ return
2250
+ try:
2251
+ ans = input("Save context before action? [Y/n] ").strip().lower()
2252
+ except (EOFError, KeyboardInterrupt):
2253
+ print()
2254
+ return
2255
+ if ans == "n":
2256
+ return
2257
+ import datetime as _dt
2258
+ stamp = _dt.datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
2259
+ save_dir = os.path.join(
2260
+ BCODER_DIR if os.path.isdir(BCODER_DIR) else HOME_BCODER_DIR,
2261
+ "autosave"
2262
+ )
2263
+ os.makedirs(save_dir, exist_ok=True)
2264
+ fpath = os.path.join(save_dir, f"{stamp}.txt")
2265
+ with open(fpath, "w", encoding="utf-8") as f:
2266
+ for msg in self.messages:
2267
+ f.write(f"=== {msg['role']} ===\n{msg['content']}\n\n")
2268
+ print(f"[autosave] context saved → {fpath}")
2269
+
2246
2270
  def _print_status(self) -> None:
2247
2271
  """Print a single status line showing model, size, quant, native ctx, and usage."""
2248
2272
  est_tokens = sum(len(m["content"]) for m in self.messages) // 4
@@ -2253,6 +2277,7 @@ class CoderCLI:
2253
2277
  parts.append(_fmt_ctx(self._meta_ctx))
2254
2278
  meta = f" [{' '.join(parts)}]" if parts else ""
2255
2279
  print(f"\033[2m {model_str}{meta} │ ctx {est_tokens} / {self.num_ctx} ({pct}%)\033[0m")
2280
+ print()
2256
2281
 
2257
2282
  def __init__(self, base_url, model, models, provider="ollama"):
2258
2283
  self.base_url = base_url
@@ -2350,6 +2375,8 @@ class CoderCLI:
2350
2375
  ) as resp:
2351
2376
  resp.raise_for_status()
2352
2377
  in_think = False
2378
+ _had_thinking = False
2379
+ _sep_done = False
2353
2380
  for line in resp.iter_lines():
2354
2381
  if not line:
2355
2382
  continue
@@ -2367,6 +2394,7 @@ class CoderCLI:
2367
2394
  reasoning = delta.get("reasoning_content") or ""
2368
2395
  if reasoning and self.think_show:
2369
2396
  _print(f"\033[90m{reasoning}\033[0m")
2397
+ _had_thinking = True
2370
2398
  chunk = delta.get("content") or ""
2371
2399
  if chunk:
2372
2400
  # apply <think>...</think> state machine (same as Ollama path)
@@ -2385,6 +2413,9 @@ class CoderCLI:
2385
2413
  else:
2386
2414
  start = chunk.find('<think>')
2387
2415
  if start == -1:
2416
+ if _had_thinking and not _sep_done:
2417
+ _print("\n")
2418
+ _sep_done = True
2388
2419
  _print(chunk)
2389
2420
  chunks.append(chunk)
2390
2421
  chunk = ""
@@ -2393,6 +2424,7 @@ class CoderCLI:
2393
2424
  _print(chunk[:start])
2394
2425
  chunks.append(chunk[:start])
2395
2426
  in_think = True
2427
+ _had_thinking = True
2396
2428
  chunk = chunk[start + 7:]
2397
2429
  else:
2398
2430
  opts = {"num_ctx": self.num_ctx}
@@ -2405,6 +2437,8 @@ class CoderCLI:
2405
2437
  ) as resp:
2406
2438
  resp.raise_for_status()
2407
2439
  in_think = False
2440
+ _had_thinking = False
2441
+ _sep_done = False
2408
2442
  for line in resp.iter_lines():
2409
2443
  if not line:
2410
2444
  continue
@@ -2414,6 +2448,7 @@ class CoderCLI:
2414
2448
  thinking = msg.get("thinking", "")
2415
2449
  if thinking and self.think_show:
2416
2450
  _print(f"\033[90m{thinking}\033[0m")
2451
+ _had_thinking = True
2417
2452
  chunk = msg.get("content", "")
2418
2453
  if chunk:
2419
2454
  # State machine: track <think>...</think> across tokens
@@ -2432,6 +2467,9 @@ class CoderCLI:
2432
2467
  else:
2433
2468
  start = chunk.find('<think>')
2434
2469
  if start == -1:
2470
+ if _had_thinking and not _sep_done:
2471
+ _print("\n")
2472
+ _sep_done = True
2435
2473
  _print(chunk)
2436
2474
  chunks.append(chunk)
2437
2475
  chunk = ""
@@ -2440,6 +2478,7 @@ class CoderCLI:
2440
2478
  _print(chunk[:start])
2441
2479
  chunks.append(chunk[:start])
2442
2480
  in_think = True
2481
+ _had_thinking = True
2443
2482
  chunk = chunk[start + len('<think>'):]
2444
2483
  if data.get("done"):
2445
2484
  break
@@ -2484,9 +2523,9 @@ class CoderCLI:
2484
2523
  self._apply_config(_session_cfg)
2485
2524
  print()
2486
2525
  self._translate_autoload()
2526
+ self._print_status()
2487
2527
  while True:
2488
2528
  try:
2489
- self._print_status()
2490
2529
  user_input = input("> ").strip()
2491
2530
  except (EOFError, KeyboardInterrupt):
2492
2531
  print()
@@ -2496,6 +2535,7 @@ class CoderCLI:
2496
2535
  if user_input not in self._history or (self._history and self._history[-1] != user_input):
2497
2536
  self._history.append(user_input)
2498
2537
  self._route(user_input)
2538
+ self._print_status()
2499
2539
  if user_input.startswith("/"):
2500
2540
  import shlex as _shlex
2501
2541
  _args = user_input.split(None, 1)[1] if " " in user_input else ""
@@ -2569,6 +2609,7 @@ class CoderCLI:
2569
2609
  return
2570
2610
 
2571
2611
  if user_input == "/exit":
2612
+ self._autosave_prompt()
2572
2613
  sys.exit(0)
2573
2614
  elif user_input == "/about":
2574
2615
  self._cmd_about()
@@ -2940,6 +2981,10 @@ advanced_tools =
2940
2981
  print(f"[no messages found in {load_path}]")
2941
2982
  return
2942
2983
  self.messages.extend(loaded)
2984
+ last_a = next((m["content"] for m in reversed(loaded) if m["role"] == "assistant"), "")
2985
+ if last_a:
2986
+ self.last_reply = last_a
2987
+ self._last_output = last_a
2943
2988
  print(f"[loaded {len(loaded)} messages from {load_path}]")
2944
2989
  except FileNotFoundError:
2945
2990
  print(f"file not found: {load_path}")
@@ -3086,6 +3131,7 @@ advanced_tools =
3086
3131
  print("[ctx compact] failed — context unchanged")
3087
3132
  return
3088
3133
 
3134
+ self._autosave_prompt()
3089
3135
  if use_savepoint:
3090
3136
  del self.messages[self._savepoint:]
3091
3137
  self.messages.append({"role": "user", "content": f"[summary since savepoint]\n{summary}"})
@@ -4984,7 +5030,21 @@ advanced_tools =
4984
5030
  try:
4985
5031
  if mode == "online":
4986
5032
  from deep_translator import GoogleTranslator as _GT
4987
- return _GT(source=from_lang, target=to_lang).translate(text)
5033
+ _MAX = 4500
5034
+ if len(text) <= _MAX:
5035
+ return _GT(source=from_lang, target=to_lang).translate(text) or text
5036
+ # chunk by paragraphs to stay under Google's limit
5037
+ _parts, _buf, _results = text.split("\n\n"), "", []
5038
+ for _p in _parts:
5039
+ if len(_buf) + len(_p) + 2 <= _MAX:
5040
+ _buf = (_buf + "\n\n" + _p) if _buf else _p
5041
+ else:
5042
+ if _buf:
5043
+ _results.append(_GT(source=from_lang, target=to_lang).translate(_buf) or _buf)
5044
+ _buf = _p
5045
+ if _buf:
5046
+ _results.append(_GT(source=from_lang, target=to_lang).translate(_buf) or _buf)
5047
+ return "\n\n".join(_results)
4988
5048
  elif mode == "lm":
4989
5049
  cfg = self._translate_load_cfg()
4990
5050
  lm_timeout = int(cfg.get("lm_timeout", 120))
@@ -5567,7 +5627,10 @@ Config stored in ~/.1bcoder/translate.json
5567
5627
  translated = self._translate_run(self.last_reply, "en", lang, mode=mode)
5568
5628
  self.last_translated_reply = translated
5569
5629
  print(f"\n{_LBLUE}─── {lang.upper()} ───{_R}")
5570
- print(translated)
5630
+ if translated:
5631
+ print(translated)
5632
+ else:
5633
+ print("[translate] translation returned empty result — check language code or network")
5571
5634
  return
5572
5635
 
5573
5636
  print("usage: /translate setup [lang:uk] [mode:lm] [host:<url>] [model:<name>] [profile:<name>]")
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "1bcoder"
7
- version = "0.1.8"
7
+ version = "0.1.9"
8
8
  description = "AI coding assistant agent for 1B–7B local models (Ollama, LMStudio, llama.cpp). Terminal REPL with file editing, project map, agents, scripts, and parallel multi-model queries."
9
9
  requires-python = ">=3.10"
10
10
  readme = {file = "README.md", content-type = "text/markdown"}
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes