mlx-code 0.0.21__tar.gz → 0.0.23__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 (27) hide show
  1. {mlx_code-0.0.21 → mlx_code-0.0.23}/PKG-INFO +19 -22
  2. {mlx_code-0.0.21 → mlx_code-0.0.23}/README.md +18 -21
  3. {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code/repl.py +45 -14
  4. {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code.egg-info/PKG-INFO +19 -22
  5. {mlx_code-0.0.21 → mlx_code-0.0.23}/setup.py +1 -1
  6. {mlx_code-0.0.21 → mlx_code-0.0.23}/LICENSE +0 -0
  7. {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code/__init__.py +0 -0
  8. {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code/apis.py +0 -0
  9. {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code/gits.py +0 -0
  10. {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code/lsp_tool.py +0 -0
  11. {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code/main.py +0 -0
  12. {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code/mcb.py +0 -0
  13. {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code/mcb_tool.py +0 -0
  14. {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code/ntui.py +0 -0
  15. {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code/stream_log.py +0 -0
  16. {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code/tools.py +0 -0
  17. {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code/util.py +0 -0
  18. {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code/view_git.py +0 -0
  19. {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code/view_log.py +0 -0
  20. {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code.egg-info/SOURCES.txt +0 -0
  21. {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code.egg-info/dependency_links.txt +0 -0
  22. {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code.egg-info/entry_points.txt +0 -0
  23. {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code.egg-info/requires.txt +0 -0
  24. {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code.egg-info/top_level.txt +0 -0
  25. {mlx_code-0.0.21 → mlx_code-0.0.23}/setup.cfg +0 -0
  26. {mlx_code-0.0.21 → mlx_code-0.0.23}/tests/__init__.py +0 -0
  27. {mlx_code-0.0.21 → mlx_code-0.0.23}/tests/test.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mlx-code
3
- Version: 0.0.21
3
+ Version: 0.0.23
4
4
  Summary: Coding Agent for Mac
5
5
  Home-page: https://josefalbers.github.io/mlx-code/
6
6
  Author: J Joe
@@ -38,7 +38,7 @@ Dynamic: summary
38
38
 
39
39
  A Git-native coding agent that can run entirely on your Mac. No API keys, no cloud, and no data leaving your machine. Powered by Apple MLX, it turns commits, branches, and worktrees into the agent’s state, history, and execution model
40
40
 
41
- https://github.com/user-attachments/assets/0569d101-8d0a-4e67-9e82-fce84a5ef3f0
41
+ [![Link](https://raw.githubusercontent.com/JosefAlbers/mlx-code/main/assets/mlx-code-v0.0.20.gif)](https://youtu.be/0lkY7YQCyCo)
42
42
 
43
43
  ---
44
44
 
@@ -68,19 +68,19 @@ REPL tabs (each tab = a git branch + agent) │
68
68
 
69
69
  ├────────────────────────────────────► each tab is an independent Agent
70
70
 
71
- ┌────┴────────────────────────────────┐
72
- │ Agent
73
- │ ┌──────────────┐ ┌──────────────┐
74
- │ │ API: │ │ Tools: │
75
- │ │ MLX (local) │ │ Read Write │
76
- │ │ Claude │ │ Edit Bash │
77
- │ │ Gemini │ │ Grep Find │
78
- │ │ OpenAI │ │ Ls Skill │
79
- │ └──────────────┘ │ Agent ───────┼─┼───► spawns child Agent
80
- │ └──────────────┘ │ (each with own tools + worktree + etc)
81
- │ Git worktree
82
- │ (isolation + session state)
83
- └─────────────────────────────────────┘
71
+ ┌────┴─────────────────────────────────┐
72
+ │ Agent
73
+ │ ┌──────────────┐ ┌──────────────┐
74
+ │ │ API: │ │ Tools: │
75
+ │ │ MLX (local) │ │ Read Write │
76
+ │ │ Claude │ │ Edit Bash │
77
+ │ │ Gemini │ │ Grep Find │
78
+ │ │ OpenAI │ │ Ls Skill │
79
+ │ └──────────────┘ │ Agent ───────┼──┼───► spawns child Agent
80
+ │ └──────────────┘ │ (each with own tools + worktree + etc)
81
+ │ Git worktree
82
+ │ (isolation + session state)
83
+ └──────────────────────────────────────┘
84
84
  ```
85
85
 
86
86
  Each layer is importable and composable on its own. A commit records state, a branch records an alternative path, and a tab is just a live view over an `Agent`.
@@ -106,8 +106,6 @@ mlc-run --api deepseek --model deepseek-v4-flash
106
106
 
107
107
  That's it. The first run starts a local inference server and drops you into the REPL.
108
108
 
109
- [![Link](https://raw.githubusercontent.com/JosefAlbers/mlx-code/main/assets/mlx-code-v0.0.20.gif)](https://youtu.be/0lkY7YQCyCo)
110
-
111
109
  ---
112
110
 
113
111
  ## Core ideas
@@ -312,7 +310,6 @@ echo "explain lsp.py" | mlc-run -a deepseek | cat - PLAN.md | mlc-run --url http
312
310
  mlc-run --notui
313
311
  ```
314
312
 
315
-
316
313
  ---
317
314
 
318
315
  ## Using as a Library
@@ -444,9 +441,9 @@ agent = Agent(extra_tool_classes=[LiveDBTool], tool_names=["QueryDB"])
444
441
  | `/branch [--rev N] [prompt]` | Open a new branch tab from the current (or earlier) checkpoint |
445
442
  | `/abort` | Abort the running agent |
446
443
  | `/export [path]` | Export session to JSON |
447
- | `/exit` or `/quit` | Close branch tab, or exit the app |
444
+ | `/exit [--all]` | Close branch tab, or exit the app |
448
445
  | `!command` | Run a shell command; output captured in the TUI |
449
- | `!!command` | Run an interactive command (TUI suspends, terminal handed to process) |
446
+ | `$command` | Run an interactive command (TUI suspends, terminal handed to process) |
450
447
 
451
448
  ### Key bindings
452
449
 
@@ -454,8 +451,8 @@ agent = Agent(extra_tool_classes=[LiveDBTool], tool_names=["QueryDB"])
454
451
  |---|---|
455
452
  | `Enter` | Submit |
456
453
  | `Ctrl-J` | Insert newline |
457
- | `Alt-1` … `Alt-9` | Jump to tab N |
458
- | `Tab` / `Shift-Tab` | Cycle through tabs |
454
+ | `Ctrl-1` … `Ctrl-9` | Jump to tab N |
455
+ | `Ctrl-,` / `Ctrl-.` | Cycle through tabs |
459
456
  | `Ctrl-C` | Abort running agent |
460
457
  | `Ctrl-D` | Close branch tab, or exit app |
461
458
  | `Ctrl-R` | Recall last prompt into editor |
@@ -2,7 +2,7 @@
2
2
 
3
3
  A Git-native coding agent that can run entirely on your Mac. No API keys, no cloud, and no data leaving your machine. Powered by Apple MLX, it turns commits, branches, and worktrees into the agent’s state, history, and execution model
4
4
 
5
- https://github.com/user-attachments/assets/0569d101-8d0a-4e67-9e82-fce84a5ef3f0
5
+ [![Link](https://raw.githubusercontent.com/JosefAlbers/mlx-code/main/assets/mlx-code-v0.0.20.gif)](https://youtu.be/0lkY7YQCyCo)
6
6
 
7
7
  ---
8
8
 
@@ -32,19 +32,19 @@ REPL tabs (each tab = a git branch + agent) │
32
32
 
33
33
  ├────────────────────────────────────► each tab is an independent Agent
34
34
 
35
- ┌────┴────────────────────────────────┐
36
- │ Agent
37
- │ ┌──────────────┐ ┌──────────────┐
38
- │ │ API: │ │ Tools: │
39
- │ │ MLX (local) │ │ Read Write │
40
- │ │ Claude │ │ Edit Bash │
41
- │ │ Gemini │ │ Grep Find │
42
- │ │ OpenAI │ │ Ls Skill │
43
- │ └──────────────┘ │ Agent ───────┼─┼───► spawns child Agent
44
- │ └──────────────┘ │ (each with own tools + worktree + etc)
45
- │ Git worktree
46
- │ (isolation + session state)
47
- └─────────────────────────────────────┘
35
+ ┌────┴─────────────────────────────────┐
36
+ │ Agent
37
+ │ ┌──────────────┐ ┌──────────────┐
38
+ │ │ API: │ │ Tools: │
39
+ │ │ MLX (local) │ │ Read Write │
40
+ │ │ Claude │ │ Edit Bash │
41
+ │ │ Gemini │ │ Grep Find │
42
+ │ │ OpenAI │ │ Ls Skill │
43
+ │ └──────────────┘ │ Agent ───────┼──┼───► spawns child Agent
44
+ │ └──────────────┘ │ (each with own tools + worktree + etc)
45
+ │ Git worktree
46
+ │ (isolation + session state)
47
+ └──────────────────────────────────────┘
48
48
  ```
49
49
 
50
50
  Each layer is importable and composable on its own. A commit records state, a branch records an alternative path, and a tab is just a live view over an `Agent`.
@@ -70,8 +70,6 @@ mlc-run --api deepseek --model deepseek-v4-flash
70
70
 
71
71
  That's it. The first run starts a local inference server and drops you into the REPL.
72
72
 
73
- [![Link](https://raw.githubusercontent.com/JosefAlbers/mlx-code/main/assets/mlx-code-v0.0.20.gif)](https://youtu.be/0lkY7YQCyCo)
74
-
75
73
  ---
76
74
 
77
75
  ## Core ideas
@@ -276,7 +274,6 @@ echo "explain lsp.py" | mlc-run -a deepseek | cat - PLAN.md | mlc-run --url http
276
274
  mlc-run --notui
277
275
  ```
278
276
 
279
-
280
277
  ---
281
278
 
282
279
  ## Using as a Library
@@ -408,9 +405,9 @@ agent = Agent(extra_tool_classes=[LiveDBTool], tool_names=["QueryDB"])
408
405
  | `/branch [--rev N] [prompt]` | Open a new branch tab from the current (or earlier) checkpoint |
409
406
  | `/abort` | Abort the running agent |
410
407
  | `/export [path]` | Export session to JSON |
411
- | `/exit` or `/quit` | Close branch tab, or exit the app |
408
+ | `/exit [--all]` | Close branch tab, or exit the app |
412
409
  | `!command` | Run a shell command; output captured in the TUI |
413
- | `!!command` | Run an interactive command (TUI suspends, terminal handed to process) |
410
+ | `$command` | Run an interactive command (TUI suspends, terminal handed to process) |
414
411
 
415
412
  ### Key bindings
416
413
 
@@ -418,8 +415,8 @@ agent = Agent(extra_tool_classes=[LiveDBTool], tool_names=["QueryDB"])
418
415
  |---|---|
419
416
  | `Enter` | Submit |
420
417
  | `Ctrl-J` | Insert newline |
421
- | `Alt-1` … `Alt-9` | Jump to tab N |
422
- | `Tab` / `Shift-Tab` | Cycle through tabs |
418
+ | `Ctrl-1` … `Ctrl-9` | Jump to tab N |
419
+ | `Ctrl-,` / `Ctrl-.` | Cycle through tabs |
423
420
  | `Ctrl-C` | Abort running agent |
424
421
  | `Ctrl-D` | Close branch tab, or exit app |
425
422
  | `Ctrl-R` | Recall last prompt into editor |
@@ -256,14 +256,14 @@ def append_to_history_table(tbl: Table, messages: list[dict]) -> None:
256
256
  if render_as_md:
257
257
  body = Markdown(text)
258
258
  else:
259
- body = RichText(escape(text), style=style)
259
+ body = RichText(text, style=style)
260
260
  tbl.add_row(RichText(prefix, style=style), body)
261
261
 
262
262
  def render_history(messages: list[dict]) -> Table:
263
263
  tbl = _make_empty_history_table()
264
264
  append_to_history_table(tbl, messages)
265
265
  return tbl
266
- REPL_HELP = '\nCommands:\n/help show this message\n/clear [--config F] clear conversation; --config reconfigures agent from YAML/JSON\n/history show full conversation transcript\n/history --raw show raw API message log (debug)\n/diff [--all] show side-by-side diff of changes\n/errors show timestamped error log for this tab\n/tools list active tools\n/branch [--rev N] [--no-worktree] [prompt]\n open a branch tab; optional prompt runs immediately\n/abort abort the running agent\n/export [path] export session to JSON\n/exit /quit close branch tab, or exit the app\n!command run shell command in worktree (output captured in TUI)\n!!command run interactive shell command (TUI suspends, terminal handed to process)\n e.g. !ls !git diff !cat file.py\n !!vim file.py !!yazi !!less log.txt\nKeys:\nEnter submit\nCtrl-J insert newline in editor\nAlt-1 … Alt-9 jump directly to tab N\nTab / Shift-Tab cycle through tabs\nCtrl-C abort running agent\nCtrl-D close branch tab, or exit app\nCtrl-R recall last prompt into editor\n'
266
+ REPL_HELP = '\nCommands:\n/help show this message\n/clear [--config F] clear conversation; --config reconfigures agent from YAML/JSON\n/history show full conversation transcript\n/history --raw show raw API message log (debug)\n/diff [--all] show side-by-side diff of changes\n/errors show timestamped error log for this tab\n/tools list active tools\n/branch [--rev N] [--no-worktree] [prompt]\n open a branch tab; optional prompt runs immediately\n/abort abort the running agent\n/export [path] export session to JSON\n/exit /quit [--all] close branch tab, or exit the app\n!command run shell command in worktree (output captured in TUI)\n$command run interactive shell command (TUI suspends, terminal handed to process)\n e.g. !ls !git diff !cat file.py\n $vim file.py $yazi $less log.txt\nKeys:\nEnter submit\nCtrl-J insert newline in editor\nCtrl-1 … Ctrl-9 jump directly to tab N\nCtrl-, / Ctrl-. cycle through tabs\nCtrl-C abort running agent\nCtrl-D close branch tab (exit app if last tab) \nCtrl-R recall last prompt into editor\n'
267
267
 
268
268
  class InputBox(TextArea):
269
269
  BINDINGS = [Binding('ctrl+j', 'insert_newline', 'New line', show=False), Binding('enter', 'submit_text', 'Submit', show=False, priority=True), Binding('ctrl+r', 'recall_last', 'Recall', show=False), Binding('ctrl+d', 'request_close', 'Exit', show=False, priority=True)]
@@ -486,7 +486,7 @@ class StatusBar(Static):
486
486
  class HelpBar(Static):
487
487
 
488
488
  def __init__(self, **kwargs):
489
- self._idle_text = RichText('/help !cmd !!interactive Ctrl-J newline Alt-1…9 tabs Ctrl-C abort Ctrl-D exit', style='dim')
489
+ self._idle_text = RichText('/help !cmd $interactive Ctrl-J newline Ctrl-,. tabs Ctrl-C abort Ctrl-D exit', style='dim')
490
490
  super().__init__(self._idle_text, **kwargs)
491
491
 
492
492
  def show_idle(self) -> None:
@@ -506,7 +506,7 @@ class HelpBar(Static):
506
506
 
507
507
  class ReplApp(App[None]):
508
508
  CSS = '\n ReplApp { layout: vertical; background: $background; }\n ContentSwitcher { height: 1fr; }\n InputBox {\n height: auto;\n min-height: 3;\n max-height: 8;\n border: none;\n border-top: tall $panel-darken-1;\n background: $panel;\n padding: 0 2;\n color: $text;\n }\n InputBox:focus { border-top: tall $accent; }\n TabBar { height: 1; background: $panel; padding: 0 1; }\n StatusBar { height: 1; background: $panel; color: $text-muted; padding: 0 1; }\n HelpBar { height: 1; color: $text-muted; padding: 0 1; }\n '
509
- BINDINGS = [Binding('ctrl+c', 'abort_agent', 'Abort', priority=True, show=False), Binding('ctrl+d', 'close_or_exit', 'Exit', show=False), Binding('tab', 'next_tab', 'Next tab', show=False), Binding('shift+tab', 'prev_tab', 'Prev tab', show=False), Binding('ctrl+1', 'switch_tab(1)', 'Tab 1', show=False), Binding('ctrl+2', 'switch_tab(2)', 'Tab 2', show=False), Binding('ctrl+3', 'switch_tab(3)', 'Tab 3', show=False), Binding('ctrl+4', 'switch_tab(4)', 'Tab 4', show=False), Binding('ctrl+5', 'switch_tab(5)', 'Tab 5', show=False), Binding('ctrl+6', 'switch_tab(6)', 'Tab 6', show=False), Binding('ctrl+7', 'switch_tab(7)', 'Tab 7', show=False), Binding('ctrl+8', 'switch_tab(8)', 'Tab 8', show=False), Binding('ctrl+9', 'switch_tab(9)', 'Tab 9', show=False)]
509
+ BINDINGS = [Binding('ctrl+c', 'abort_agent', 'Abort', priority=True, show=False), Binding('ctrl+d', 'close_or_exit', 'Exit', show=False), Binding('ctrl+full_stop', 'next_tab', 'Next tab', show=False, priority=True), Binding('ctrl+comma', 'prev_tab', 'Prev tab', show=False, priority=True), Binding('ctrl+1', 'switch_tab(1)', 'Tab 1', show=False), Binding('ctrl+2', 'switch_tab(2)', 'Tab 2', show=False), Binding('ctrl+3', 'switch_tab(3)', 'Tab 3', show=False), Binding('ctrl+4', 'switch_tab(4)', 'Tab 4', show=False), Binding('ctrl+5', 'switch_tab(5)', 'Tab 5', show=False), Binding('ctrl+6', 'switch_tab(6)', 'Tab 6', show=False), Binding('ctrl+7', 'switch_tab(7)', 'Tab 7', show=False), Binding('ctrl+8', 'switch_tab(8)', 'Tab 8', show=False), Binding('ctrl+9', 'switch_tab(9)', 'Tab 9', show=False), Binding('ctrl+z', 'suspend_app', 'Suspend', show=False, priority=True)]
510
510
 
511
511
  def __init__(self, agent: Agent, init_prompt: str | None=None) -> None:
512
512
  super().__init__()
@@ -543,6 +543,11 @@ class ReplApp(App[None]):
543
543
  except Exception:
544
544
  pass
545
545
 
546
+ def action_suspend_app(self) -> None:
547
+ import signal
548
+ with self.suspend():
549
+ os.kill(os.getpid(), signal.SIGTSTP)
550
+
546
551
  @property
547
552
  def active_tab(self) -> Tab:
548
553
  return self.tabs[self.active_index]
@@ -579,8 +584,8 @@ class ReplApp(App[None]):
579
584
  tab.errors.clear()
580
585
  tab.last_error = ''
581
586
  self.query_one('#helpbar', HelpBar).show_idle()
582
- if text.startswith('!!'):
583
- command = text[2:].strip()
587
+ if text.startswith('$'):
588
+ command = text[1:].strip()
584
589
  if command:
585
590
  await self._run_interactive_command(tab, command)
586
591
  return
@@ -593,9 +598,6 @@ class ReplApp(App[None]):
593
598
  if text.startswith('/'):
594
599
  await self._handle_command(tab, text)
595
600
  return
596
- if text.lower() in {'exit', 'quit'}:
597
- self._do_close_or_exit()
598
- return
599
601
  if tab.is_running:
600
602
  self.query_one('#helpbar', HelpBar).show_error('Agent is running — /abort first.')
601
603
  return
@@ -644,11 +646,11 @@ class ReplApp(App[None]):
644
646
  env = tab.agent.ctx.get('env')
645
647
 
646
648
  def _blocking_run() -> int:
647
- return subprocess.run(command, shell=True, cwd=cwd, env=env if env else None).returncode
649
+ return subprocess.run(command, shell=True, cwd=cwd, env={**os.environ, **env}).returncode
648
650
  with self.suspend():
649
651
  loop = asyncio.get_running_loop()
650
652
  returncode = await loop.run_in_executor(None, _blocking_run)
651
- tab.show_command(f'!!{command}', f'[exited {returncode}]')
653
+ tab.show_command(f'${command}', f'[exited {returncode}]')
652
654
 
653
655
  async def _handle_command(self, tab: Tab, text: str) -> None:
654
656
  cmd, _, arg = text.partition(' ')
@@ -708,7 +710,7 @@ class ReplApp(App[None]):
708
710
  content = m.get('content', '')
709
711
  if isinstance(content, list):
710
712
  content = ' '.join((b.get('text', '') for b in content if isinstance(b, dict) and b.get('type') == 'text'))
711
- content = re.sub('\\s+', ' ', content).strip()
713
+ content = re.sub('\\s+', ' ', content).strip()
712
714
  if len(content) > 100:
713
715
  content = content[:100] + '…'
714
716
  line = f'{i}. {content}'
@@ -874,11 +876,19 @@ class ReplApp(App[None]):
874
876
  except OSError as exc:
875
877
  self.query_one('#helpbar', HelpBar).show_error(f'Export failed: {exc}')
876
878
  elif cmd in {'/exit', '/quit'}:
877
- self._exit_with_summary(tab)
879
+ if arg == '--all':
880
+ self._exit_with_summary(tab)
881
+ else:
882
+ self._do_close_or_exit()
878
883
  else:
879
884
  self.query_one('#helpbar', HelpBar).show_error(f'Unknown command: {cmd!r} — try /help')
880
885
 
881
886
  def _exit_with_summary(self, exit_tab: Tab) -> None:
887
+ for t in self.tabs:
888
+ if t.is_running:
889
+ t.agent.abort()
890
+ if t.running_task:
891
+ t.running_task.cancel()
882
892
  summary = []
883
893
  for t in self.tabs:
884
894
  gwt = t.agent.ctx.get('gwt')
@@ -939,7 +949,18 @@ class ReplApp(App[None]):
939
949
  if tab.running_task:
940
950
  tab.running_task.cancel()
941
951
  self._confirm_close = False
942
- self._exit_with_summary(tab)
952
+ if len(self.tabs) > 1:
953
+ key = id(tab.agent)
954
+ if key in self._unsubscribers:
955
+ self._unsubscribers[key]()
956
+ del self._unsubscribers[key]
957
+ tab.remove()
958
+ self.tabs.pop(self.active_index)
959
+ if self.active_index >= len(self.tabs):
960
+ self.active_index = len(self.tabs) - 1
961
+ self._switch_to(self.active_index)
962
+ else:
963
+ self._exit_with_summary(tab)
943
964
 
944
965
  def action_abort_agent(self) -> None:
945
966
  input_box = self.query_one(InputBox)
@@ -1047,6 +1068,16 @@ def run_repl(*, base_url=None, model=None, api: Literal['claude', 'codex', 'gemi
1047
1068
  finally:
1048
1069
  if log_fp:
1049
1070
  log_fp.close()
1071
+ if app_instance:
1072
+ cleaned = set()
1073
+ for t in app_instance.tabs:
1074
+ gwt = t.agent.ctx.get('gwt')
1075
+ if gwt and getattr(gwt, 'worktree', None) and (gwt.worktree not in cleaned):
1076
+ cleaned.add(gwt.worktree)
1077
+ try:
1078
+ cleanup_worktree(gwt)
1079
+ except Exception:
1080
+ pass
1050
1081
  if app_instance and hasattr(app_instance, '_exit_summary') and app_instance._exit_summary:
1051
1082
  print('\n--- Session Exit Summary ---')
1052
1083
  for item in app_instance._exit_summary:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mlx-code
3
- Version: 0.0.21
3
+ Version: 0.0.23
4
4
  Summary: Coding Agent for Mac
5
5
  Home-page: https://josefalbers.github.io/mlx-code/
6
6
  Author: J Joe
@@ -38,7 +38,7 @@ Dynamic: summary
38
38
 
39
39
  A Git-native coding agent that can run entirely on your Mac. No API keys, no cloud, and no data leaving your machine. Powered by Apple MLX, it turns commits, branches, and worktrees into the agent’s state, history, and execution model
40
40
 
41
- https://github.com/user-attachments/assets/0569d101-8d0a-4e67-9e82-fce84a5ef3f0
41
+ [![Link](https://raw.githubusercontent.com/JosefAlbers/mlx-code/main/assets/mlx-code-v0.0.20.gif)](https://youtu.be/0lkY7YQCyCo)
42
42
 
43
43
  ---
44
44
 
@@ -68,19 +68,19 @@ REPL tabs (each tab = a git branch + agent) │
68
68
 
69
69
  ├────────────────────────────────────► each tab is an independent Agent
70
70
 
71
- ┌────┴────────────────────────────────┐
72
- │ Agent
73
- │ ┌──────────────┐ ┌──────────────┐
74
- │ │ API: │ │ Tools: │
75
- │ │ MLX (local) │ │ Read Write │
76
- │ │ Claude │ │ Edit Bash │
77
- │ │ Gemini │ │ Grep Find │
78
- │ │ OpenAI │ │ Ls Skill │
79
- │ └──────────────┘ │ Agent ───────┼─┼───► spawns child Agent
80
- │ └──────────────┘ │ (each with own tools + worktree + etc)
81
- │ Git worktree
82
- │ (isolation + session state)
83
- └─────────────────────────────────────┘
71
+ ┌────┴─────────────────────────────────┐
72
+ │ Agent
73
+ │ ┌──────────────┐ ┌──────────────┐
74
+ │ │ API: │ │ Tools: │
75
+ │ │ MLX (local) │ │ Read Write │
76
+ │ │ Claude │ │ Edit Bash │
77
+ │ │ Gemini │ │ Grep Find │
78
+ │ │ OpenAI │ │ Ls Skill │
79
+ │ └──────────────┘ │ Agent ───────┼──┼───► spawns child Agent
80
+ │ └──────────────┘ │ (each with own tools + worktree + etc)
81
+ │ Git worktree
82
+ │ (isolation + session state)
83
+ └──────────────────────────────────────┘
84
84
  ```
85
85
 
86
86
  Each layer is importable and composable on its own. A commit records state, a branch records an alternative path, and a tab is just a live view over an `Agent`.
@@ -106,8 +106,6 @@ mlc-run --api deepseek --model deepseek-v4-flash
106
106
 
107
107
  That's it. The first run starts a local inference server and drops you into the REPL.
108
108
 
109
- [![Link](https://raw.githubusercontent.com/JosefAlbers/mlx-code/main/assets/mlx-code-v0.0.20.gif)](https://youtu.be/0lkY7YQCyCo)
110
-
111
109
  ---
112
110
 
113
111
  ## Core ideas
@@ -312,7 +310,6 @@ echo "explain lsp.py" | mlc-run -a deepseek | cat - PLAN.md | mlc-run --url http
312
310
  mlc-run --notui
313
311
  ```
314
312
 
315
-
316
313
  ---
317
314
 
318
315
  ## Using as a Library
@@ -444,9 +441,9 @@ agent = Agent(extra_tool_classes=[LiveDBTool], tool_names=["QueryDB"])
444
441
  | `/branch [--rev N] [prompt]` | Open a new branch tab from the current (or earlier) checkpoint |
445
442
  | `/abort` | Abort the running agent |
446
443
  | `/export [path]` | Export session to JSON |
447
- | `/exit` or `/quit` | Close branch tab, or exit the app |
444
+ | `/exit [--all]` | Close branch tab, or exit the app |
448
445
  | `!command` | Run a shell command; output captured in the TUI |
449
- | `!!command` | Run an interactive command (TUI suspends, terminal handed to process) |
446
+ | `$command` | Run an interactive command (TUI suspends, terminal handed to process) |
450
447
 
451
448
  ### Key bindings
452
449
 
@@ -454,8 +451,8 @@ agent = Agent(extra_tool_classes=[LiveDBTool], tool_names=["QueryDB"])
454
451
  |---|---|
455
452
  | `Enter` | Submit |
456
453
  | `Ctrl-J` | Insert newline |
457
- | `Alt-1` … `Alt-9` | Jump to tab N |
458
- | `Tab` / `Shift-Tab` | Cycle through tabs |
454
+ | `Ctrl-1` … `Ctrl-9` | Jump to tab N |
455
+ | `Ctrl-,` / `Ctrl-.` | Cycle through tabs |
459
456
  | `Ctrl-C` | Abort running agent |
460
457
  | `Ctrl-D` | Close branch tab, or exit app |
461
458
  | `Ctrl-R` | Recall last prompt into editor |
@@ -11,7 +11,7 @@ setup(
11
11
  author_email="albersj66@gmail.com",
12
12
  author="J Joe",
13
13
  license="Apache-2.0",
14
- version="0.0.21",
14
+ version="0.0.23",
15
15
  readme="README.md",
16
16
  description="Coding Agent for Mac",
17
17
  long_description=open("README.md").read(),
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
File without changes
File without changes