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.
- {mlx_code-0.0.21 → mlx_code-0.0.23}/PKG-INFO +19 -22
- {mlx_code-0.0.21 → mlx_code-0.0.23}/README.md +18 -21
- {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code/repl.py +45 -14
- {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code.egg-info/PKG-INFO +19 -22
- {mlx_code-0.0.21 → mlx_code-0.0.23}/setup.py +1 -1
- {mlx_code-0.0.21 → mlx_code-0.0.23}/LICENSE +0 -0
- {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code/__init__.py +0 -0
- {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code/apis.py +0 -0
- {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code/gits.py +0 -0
- {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code/lsp_tool.py +0 -0
- {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code/main.py +0 -0
- {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code/mcb.py +0 -0
- {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code/mcb_tool.py +0 -0
- {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code/ntui.py +0 -0
- {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code/stream_log.py +0 -0
- {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code/tools.py +0 -0
- {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code/util.py +0 -0
- {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code/view_git.py +0 -0
- {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code/view_log.py +0 -0
- {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code.egg-info/SOURCES.txt +0 -0
- {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code.egg-info/dependency_links.txt +0 -0
- {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code.egg-info/entry_points.txt +0 -0
- {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code.egg-info/requires.txt +0 -0
- {mlx_code-0.0.21 → mlx_code-0.0.23}/mlx_code.egg-info/top_level.txt +0 -0
- {mlx_code-0.0.21 → mlx_code-0.0.23}/setup.cfg +0 -0
- {mlx_code-0.0.21 → mlx_code-0.0.23}/tests/__init__.py +0 -0
- {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.
|
|
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://
|
|
41
|
+
[](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
|
|
80
|
-
│ └──────────────┘
|
|
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
|
-
[](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
|
|
444
|
+
| `/exit [--all]` | Close branch tab, or exit the app |
|
|
448
445
|
| `!command` | Run a shell command; output captured in the TUI |
|
|
449
|
-
|
|
|
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
|
-
| `
|
|
458
|
-
| `
|
|
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://
|
|
5
|
+
[](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
|
|
44
|
-
│ └──────────────┘
|
|
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
|
-
[](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
|
|
408
|
+
| `/exit [--all]` | Close branch tab, or exit the app |
|
|
412
409
|
| `!command` | Run a shell command; output captured in the TUI |
|
|
413
|
-
|
|
|
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
|
-
| `
|
|
422
|
-
| `
|
|
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(
|
|
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
|
|
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
|
|
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('
|
|
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[
|
|
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=
|
|
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'
|
|
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+', '
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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://
|
|
41
|
+
[](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
|
|
80
|
-
│ └──────────────┘
|
|
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
|
-
[](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
|
|
444
|
+
| `/exit [--all]` | Close branch tab, or exit the app |
|
|
448
445
|
| `!command` | Run a shell command; output captured in the TUI |
|
|
449
|
-
|
|
|
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
|
-
| `
|
|
458
|
-
| `
|
|
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 |
|
|
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
|
|
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
|