mlx-code 0.0.30__tar.gz → 0.0.32__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.30 → mlx_code-0.0.32}/PKG-INFO +9 -10
- {mlx_code-0.0.30 → mlx_code-0.0.32}/README.md +3 -3
- {mlx_code-0.0.30 → mlx_code-0.0.32}/mlx_code/bats.py +20 -0
- {mlx_code-0.0.30 → mlx_code-0.0.32}/mlx_code/gits.py +14 -4
- {mlx_code-0.0.30 → mlx_code-0.0.32}/mlx_code/main.py +21 -40
- {mlx_code-0.0.30 → mlx_code-0.0.32}/mlx_code/repl.py +44 -27
- mlx_code-0.0.32/mlx_code/view_git.py +995 -0
- {mlx_code-0.0.30 → mlx_code-0.0.32}/mlx_code/web.py +37 -74
- {mlx_code-0.0.30 → mlx_code-0.0.32}/mlx_code.egg-info/PKG-INFO +9 -10
- {mlx_code-0.0.30 → mlx_code-0.0.32}/mlx_code.egg-info/requires.txt +5 -6
- {mlx_code-0.0.30 → mlx_code-0.0.32}/setup.py +12 -11
- mlx_code-0.0.30/mlx_code/view_git.py +0 -824
- {mlx_code-0.0.30 → mlx_code-0.0.32}/LICENSE +0 -0
- {mlx_code-0.0.30 → mlx_code-0.0.32}/mlx_code/__init__.py +0 -0
- {mlx_code-0.0.30 → mlx_code-0.0.32}/mlx_code/apis.py +0 -0
- {mlx_code-0.0.30 → mlx_code-0.0.32}/mlx_code/bare.py +0 -0
- {mlx_code-0.0.30 → mlx_code-0.0.32}/mlx_code/lsp_tool.py +0 -0
- {mlx_code-0.0.30 → mlx_code-0.0.32}/mlx_code/mcb.py +0 -0
- {mlx_code-0.0.30 → mlx_code-0.0.32}/mlx_code/mcb_tool.py +0 -0
- {mlx_code-0.0.30 → mlx_code-0.0.32}/mlx_code/stream_log.py +0 -0
- {mlx_code-0.0.30 → mlx_code-0.0.32}/mlx_code/tools.py +0 -0
- {mlx_code-0.0.30 → mlx_code-0.0.32}/mlx_code/tui.py +0 -0
- {mlx_code-0.0.30 → mlx_code-0.0.32}/mlx_code/util.py +0 -0
- {mlx_code-0.0.30 → mlx_code-0.0.32}/mlx_code/view_log.py +0 -0
- {mlx_code-0.0.30 → mlx_code-0.0.32}/mlx_code.egg-info/SOURCES.txt +0 -0
- {mlx_code-0.0.30 → mlx_code-0.0.32}/mlx_code.egg-info/dependency_links.txt +0 -0
- {mlx_code-0.0.30 → mlx_code-0.0.32}/mlx_code.egg-info/entry_points.txt +0 -0
- {mlx_code-0.0.30 → mlx_code-0.0.32}/mlx_code.egg-info/top_level.txt +0 -0
- {mlx_code-0.0.30 → mlx_code-0.0.32}/setup.cfg +0 -0
- {mlx_code-0.0.30 → mlx_code-0.0.32}/tests/__init__.py +0 -0
- {mlx_code-0.0.30 → mlx_code-0.0.32}/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.32
|
|
4
4
|
Summary: Coding Agent for Mac
|
|
5
5
|
Home-page: https://josefalbers.github.io/mlx-code/
|
|
6
6
|
Author: J Joe
|
|
@@ -15,14 +15,13 @@ License-File: LICENSE
|
|
|
15
15
|
Requires-Dist: mlx-lm>=0.31.3; platform_system == "Darwin"
|
|
16
16
|
Requires-Dist: httpx
|
|
17
17
|
Requires-Dist: pydantic
|
|
18
|
-
Requires-Dist: textual>=8.2.7
|
|
19
|
-
Requires-Dist: rich>=15.0.0
|
|
20
|
-
Requires-Dist: starlette
|
|
21
|
-
Requires-Dist: uvicorn
|
|
22
18
|
Provides-Extra: all
|
|
23
|
-
Requires-Dist:
|
|
24
|
-
Requires-Dist:
|
|
19
|
+
Requires-Dist: starlette; extra == "all"
|
|
20
|
+
Requires-Dist: uvicorn; extra == "all"
|
|
25
21
|
Requires-Dist: pygments; extra == "all"
|
|
22
|
+
Requires-Dist: textual>=8.2.7; extra == "all"
|
|
23
|
+
Requires-Dist: rich>=15.0.0; extra == "all"
|
|
24
|
+
Requires-Dist: python-lsp-server[all]; extra == "all"
|
|
26
25
|
Dynamic: author
|
|
27
26
|
Dynamic: author-email
|
|
28
27
|
Dynamic: description
|
|
@@ -76,7 +75,7 @@ Agents: ├───────────────────
|
|
|
76
75
|
│ │ Gemini │ │ Edit Bash │ │
|
|
77
76
|
│ │ Claude │ │ Grep Find │ │
|
|
78
77
|
│ │ Codex │ │ Ls Skill │ │
|
|
79
|
-
│ │ DeepSeek │ │ Agent
|
|
78
|
+
│ │ DeepSeek │ │ Agent ────────────────► Recursively spawns sub-Agents
|
|
80
79
|
│ └────────────────┘ └────────────────┘ │
|
|
81
80
|
│ Git worktree │
|
|
82
81
|
│ (isolation + session state) │
|
|
@@ -108,10 +107,10 @@ result = await agent.run('refactor utils.py to use dataclasses')
|
|
|
108
107
|
|
|
109
108
|
```bash
|
|
110
109
|
# ephemeral run (no installation)
|
|
111
|
-
uvx --from mlx-code mlc
|
|
110
|
+
uvx --from mlx-code[all] mlc
|
|
112
111
|
|
|
113
112
|
# or install into the current environment
|
|
114
|
-
pip install mlx-code
|
|
113
|
+
pip install mlx-code[all]
|
|
115
114
|
|
|
116
115
|
# launch
|
|
117
116
|
mlc # with a local MLX model
|
|
@@ -38,7 +38,7 @@ Agents: ├───────────────────
|
|
|
38
38
|
│ │ Gemini │ │ Edit Bash │ │
|
|
39
39
|
│ │ Claude │ │ Grep Find │ │
|
|
40
40
|
│ │ Codex │ │ Ls Skill │ │
|
|
41
|
-
│ │ DeepSeek │ │ Agent
|
|
41
|
+
│ │ DeepSeek │ │ Agent ────────────────► Recursively spawns sub-Agents
|
|
42
42
|
│ └────────────────┘ └────────────────┘ │
|
|
43
43
|
│ Git worktree │
|
|
44
44
|
│ (isolation + session state) │
|
|
@@ -70,10 +70,10 @@ result = await agent.run('refactor utils.py to use dataclasses')
|
|
|
70
70
|
|
|
71
71
|
```bash
|
|
72
72
|
# ephemeral run (no installation)
|
|
73
|
-
uvx --from mlx-code mlc
|
|
73
|
+
uvx --from mlx-code[all] mlc
|
|
74
74
|
|
|
75
75
|
# or install into the current environment
|
|
76
|
-
pip install mlx-code
|
|
76
|
+
pip install mlx-code[all]
|
|
77
77
|
|
|
78
78
|
# launch
|
|
79
79
|
mlc # with a local MLX model
|
|
@@ -294,6 +294,26 @@ def make_batch_app(model_name: str, cache_dir: str='.cache'):
|
|
|
294
294
|
n_cached = sum((1 for _ in pc.cache_dir.glob('*.safetensors')))
|
|
295
295
|
return JSONResponse({'status': 'ok', 'model': model_name, 'active_sequences': len(state['active']), 'prefix_cache_files': n_cached})
|
|
296
296
|
return Starlette(routes=[Route('/v1/models', list_models, methods=['GET']), Route('/v1/messages/count_tokens', count_tokens, methods=['POST']), Route('/v1/chat/completions', generate_endpoint, methods=['POST']), Route('/v1/messages', generate_endpoint, methods=['POST']), Route('/v1/responses', generate_endpoint, methods=['POST']), Route('/v1beta/models/{rest:path}', generate_endpoint, methods=['POST']), Route('/generate', simple_generate, methods=['POST']), Route('/health', health, methods=['GET'])], lifespan=lifespan)
|
|
297
|
+
|
|
298
|
+
class BatchServer:
|
|
299
|
+
import uvicorn
|
|
300
|
+
|
|
301
|
+
def __init__(self, app, host: str, port: int):
|
|
302
|
+
config = uvicorn.Config(app, host=host, port=port, loop='asyncio', log_level='warning')
|
|
303
|
+
self._server = uvicorn.Server(config)
|
|
304
|
+
self.host = host
|
|
305
|
+
self.port = port
|
|
306
|
+
|
|
307
|
+
def serve_forever(self):
|
|
308
|
+
self._server.run()
|
|
309
|
+
|
|
310
|
+
@property
|
|
311
|
+
def started(self) -> bool:
|
|
312
|
+
return self._server.started
|
|
313
|
+
|
|
314
|
+
def make_batch_server(host: str, port: int, model, cache_dir: str='.cache') -> BatchServer:
|
|
315
|
+
app = make_batch_app(model, cache_dir=cache_dir)
|
|
316
|
+
return BatchServer(app, host, port)
|
|
297
317
|
if __name__ == '__main__':
|
|
298
318
|
import uvicorn
|
|
299
319
|
uvicorn.run(make_batch_app('mlx-community/Qwen3.5-4B-OptiQ-4bit'), host='0.0.0.0', port=8000)
|
|
@@ -9,7 +9,6 @@ import uuid
|
|
|
9
9
|
from dataclasses import dataclass
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
logger = logging.getLogger(__name__)
|
|
12
|
-
_ADD_EXCLUDES = ['_*', '*.bin', '*.gguf', '*.safetensors', '*.pt', '*.pth', '.cache/', '.log.json', '*.egg-info/', '.eggs/', 'build/', 'dist/', '__pycache__/', '*.pyc', '*.pyo', '*.pyd', '.pytest_cache/', '.tox/', '.nox/', '.coverage', 'htmlcov/', '.venv/', 'venv/', 'env/', '.DS_Store', 'Thumbs.db']
|
|
13
12
|
|
|
14
13
|
class GitError(RuntimeError):
|
|
15
14
|
pass
|
|
@@ -57,11 +56,22 @@ def _count_user_turns(commit_body: str) -> int:
|
|
|
57
56
|
if messages:
|
|
58
57
|
return sum((1 for m in messages if m.get('role') == 'user'))
|
|
59
58
|
return 0
|
|
59
|
+
_ADD_EXCLUDES = ['_*', '_*/', '*.bin', '*.gguf', '*.safetensors', '*.pt', '*.pth', '.cache/', '.log.json', '*.egg-info/', '.eggs/', 'build/', 'dist/', '__pycache__/', '*.pyc', '*.pyo', '*.pyd', '.pytest_cache/', '.tox/', '.nox/', '.coverage', 'htmlcov/', '.venv/', 'venv/', 'env/', '.DS_Store', 'Thumbs.db']
|
|
60
|
+
|
|
61
|
+
def _exclude_pathspecs(patterns: list[str]) -> list[str]:
|
|
62
|
+
specs = []
|
|
63
|
+
for p in patterns:
|
|
64
|
+
if p.endswith('/'):
|
|
65
|
+
name = p[:-1]
|
|
66
|
+
specs.append(f':(exclude,glob)**/{name}/**')
|
|
67
|
+
else:
|
|
68
|
+
specs.append(f':(exclude,glob)**/{p}')
|
|
69
|
+
return specs
|
|
60
70
|
|
|
61
71
|
def git_add_filtered(cwd: str) -> None:
|
|
62
|
-
excludes =
|
|
72
|
+
excludes = _exclude_pathspecs(_ADD_EXCLUDES)
|
|
63
73
|
try:
|
|
64
|
-
_git(cwd, 'add', '-A', '--', '.', *excludes)
|
|
74
|
+
_git(cwd, '-c', 'advice.addIgnoredFile=false', 'add', '-A', '--', '.', *excludes)
|
|
65
75
|
except GitError as e:
|
|
66
76
|
logger.warning('git add warning (ignored): %s', e)
|
|
67
77
|
|
|
@@ -83,7 +93,7 @@ def create_worktree(repo_dir: str, *, worktree_dir: str | None=None, ref: str='H
|
|
|
83
93
|
root = repo_dir
|
|
84
94
|
gi = os.path.join(root, '.gitignore')
|
|
85
95
|
if not os.path.exists(gi):
|
|
86
|
-
Path(gi).write_text('\n'.join(['
|
|
96
|
+
Path(gi).write_text('\n'.join(['.log.json']))
|
|
87
97
|
if not _git(root, 'config', 'user.email', check=False):
|
|
88
98
|
_git(root, 'config', 'user.email', 'agent@local')
|
|
89
99
|
if not _git(root, 'config', 'user.name', check=False):
|
|
@@ -890,11 +890,14 @@ def _serve_cache(host, port, model, cache, system, tools, skips, *, fixed_port=F
|
|
|
890
890
|
raise
|
|
891
891
|
|
|
892
892
|
def _serve_batch(host, port, model, cache_dir='.cache', *, fixed_port=False):
|
|
893
|
-
|
|
894
|
-
|
|
893
|
+
try:
|
|
894
|
+
from .bats import make_batch_server
|
|
895
|
+
except ImportError:
|
|
896
|
+
print()
|
|
897
|
+
print('[warning] uvicorn/starlette not installed')
|
|
898
|
+
print(' Install server deps with:\x1b[31m pip install mlx-code[all] \x1b[0m')
|
|
899
|
+
return _serve_cache(host, port, model, cache_dir, None, None, None, fixed_port=fixed_port)
|
|
895
900
|
import socket
|
|
896
|
-
import time
|
|
897
|
-
app = make_batch_app(model, cache_dir=cache_dir)
|
|
898
901
|
while True:
|
|
899
902
|
try:
|
|
900
903
|
with socket.socket() as s:
|
|
@@ -909,24 +912,10 @@ def _serve_batch(host, port, model, cache_dir='.cache', *, fixed_port=False):
|
|
|
909
912
|
raise
|
|
910
913
|
else:
|
|
911
914
|
break
|
|
912
|
-
|
|
913
|
-
uv_server = uvicorn.Server(config)
|
|
914
|
-
t = threading.Thread(target=uv_server.run, daemon=True)
|
|
915
|
-
t.start()
|
|
916
|
-
start_time = time.time()
|
|
917
|
-
notified = False
|
|
918
|
-
while True:
|
|
919
|
-
try:
|
|
920
|
-
with socket.create_connection((host, port), timeout=0.1):
|
|
921
|
-
break
|
|
922
|
-
except OSError:
|
|
923
|
-
if not notified and time.time() - start_time > 3.0:
|
|
924
|
-
logger.info('Waiting for batch server to start (model may be downloading)...')
|
|
925
|
-
notified = True
|
|
926
|
-
time.sleep(0.2)
|
|
915
|
+
server = make_batch_server(host, port, model, cache_dir=cache_dir)
|
|
927
916
|
url = f'http://{host}:{port}'
|
|
928
917
|
logger.debug(f'Batch server bound to {url}')
|
|
929
|
-
return (
|
|
918
|
+
return (server, url)
|
|
930
919
|
|
|
931
920
|
def main():
|
|
932
921
|
parser = argparse.ArgumentParser(description='mlx-code MAIN')
|
|
@@ -967,28 +956,20 @@ def main():
|
|
|
967
956
|
else:
|
|
968
957
|
server, url = _serve_cache(host=args.host, port=port, model=args.model, cache=cache, system=None if args.leash in ('none', 'noapi') else args.system, tools=args.tools, skips=args.skips, fixed_port=fixed_port, gwt=gwt)
|
|
969
958
|
if args.leash == 'none':
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
else:
|
|
976
|
-
try:
|
|
977
|
-
server.serve_forever()
|
|
978
|
-
except KeyboardInterrupt:
|
|
979
|
-
print('\nShutting down server...')
|
|
980
|
-
server.server_close()
|
|
959
|
+
try:
|
|
960
|
+
server.serve_forever()
|
|
961
|
+
except KeyboardInterrupt:
|
|
962
|
+
print('\nShutting down server...')
|
|
963
|
+
server.server_close()
|
|
981
964
|
else:
|
|
982
|
-
|
|
983
|
-
|
|
965
|
+
threading.Thread(target=server.serve_forever, daemon=True).start()
|
|
966
|
+
while not getattr(server, 'started', True):
|
|
967
|
+
time.sleep(0.05)
|
|
984
968
|
if args.leash == 'noapi':
|
|
985
|
-
if args.web
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
else:
|
|
990
|
-
from .repl import run_repl
|
|
991
|
-
run_repl(base_url=url, api=args.leash, repo=cwd, env=env, system=args.system, tool_names=args.tools, sdir=args.skill, init_prompt=args.prompt, resume=args.resume, stream=args.stream, bare=args.bare)
|
|
969
|
+
ui_mode = 'web' if args.web else 'bare' if args.bare else 'tui'
|
|
970
|
+
web_port = args.web_port if args.web_port is not None else port + 80
|
|
971
|
+
from .repl import run_repl
|
|
972
|
+
run_repl(base_url=url, api=args.leash, repo=cwd, env=env, system=args.system, tool_names=args.tools, sdir=args.skill, init_prompt=args.prompt, resume=args.resume, stream=args.stream, ui_mode=ui_mode, web_host=args.host, web_port=web_port)
|
|
992
973
|
else:
|
|
993
974
|
env['GOOGLE_GEMINI_BASE_URL'] = url
|
|
994
975
|
env['GEMINI_API_KEY'] = 'mc'
|
|
@@ -742,9 +742,9 @@ _AGENT_ENV_ALLOWLIST: re.Pattern = re.compile('\n ^(\n PATH\n | MANPATH
|
|
|
742
742
|
def _make_agent_env(base: dict[str, str]) -> dict[str, str]:
|
|
743
743
|
return {k: v for k, v in base.items() if _AGENT_ENV_ALLOWLIST.match(k)}
|
|
744
744
|
|
|
745
|
-
async def repl(engine: CommandEngine, init_prompt=None,
|
|
745
|
+
async def repl(engine: CommandEngine, init_prompt=None, ui_mode='tui'):
|
|
746
746
|
is_tty = sys.stdin.isatty() and sys.stdout.isatty()
|
|
747
|
-
if bare and is_tty:
|
|
747
|
+
if ui_mode == 'bare' and is_tty:
|
|
748
748
|
from .bare import BareRepl
|
|
749
749
|
r = BareRepl(engine, init_prompt=init_prompt)
|
|
750
750
|
await r.run()
|
|
@@ -754,12 +754,23 @@ async def repl(engine: CommandEngine, init_prompt=None, bare=False):
|
|
|
754
754
|
if user_input:
|
|
755
755
|
await _stream_to_stdout(engine.active_tab.agent, user_input)
|
|
756
756
|
return None
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
757
|
+
if ui_mode == 'tui':
|
|
758
|
+
try:
|
|
759
|
+
from .tui import ReplApp
|
|
760
|
+
except ImportError:
|
|
761
|
+
print()
|
|
762
|
+
print('[warning] textual/rich not installed → falling back to bare.')
|
|
763
|
+
print(' Install TUI deps with:\x1b[31m pip install mlx-code[all] \x1b[0m')
|
|
764
|
+
from .bare import BareRepl
|
|
765
|
+
r = BareRepl(engine, init_prompt=init_prompt)
|
|
766
|
+
await r.run()
|
|
767
|
+
return None
|
|
768
|
+
app = ReplApp(engine, init_prompt=init_prompt)
|
|
769
|
+
await app.run_async()
|
|
770
|
+
return app
|
|
771
|
+
return None
|
|
761
772
|
|
|
762
|
-
def run_repl(*, base_url=None, model=None, api
|
|
773
|
+
def run_repl(*, base_url=None, model=None, api='noapi', system='', sdir=None, skills=None, env=None, tool_names=None, extra_tool_classes=None, api_key=None, gwt=None, ctx=None, init_prompt=None, resume_messages=None, repo=None, resume=None, stream=None, ui_mode='tui', web_host='127.0.0.1', web_port=8080):
|
|
763
774
|
repo = os.path.abspath(repo or os.getcwd())
|
|
764
775
|
with tempfile.TemporaryDirectory(dir=tempfile.gettempdir()) as _home:
|
|
765
776
|
if gwt is None:
|
|
@@ -785,9 +796,6 @@ def run_repl(*, base_url=None, model=None, api: Literal['claude', 'codex', 'gemi
|
|
|
785
796
|
system = '\n\n'.join(filter(None, [system, skill_prompt]))
|
|
786
797
|
merged_ctx = {'cwd': cwd, 'user_cwd': user_cwd, 'skills': skills, 'gwt': gwt, 'env': agent_env, **(ctx or {})}
|
|
787
798
|
agent = Agent(system=system, api=api, model=model, tool_names=tool_names, extra_tool_classes=extra_tool_classes, api_key=api_key, base_url=base_url, ctx=merged_ctx)
|
|
788
|
-
engine = CommandEngine()
|
|
789
|
-
main_tab = TabModel(agent, title='main', is_main=True)
|
|
790
|
-
engine.tabs = [main_tab]
|
|
791
799
|
log_fp = None
|
|
792
800
|
if stream is not None:
|
|
793
801
|
from .stream_log import StreamLogger
|
|
@@ -800,26 +808,35 @@ def run_repl(*, base_url=None, model=None, api: Literal['claude', 'codex', 'gemi
|
|
|
800
808
|
agent.messages = list(resume_messages)
|
|
801
809
|
print(f'[resumed {len(resume_messages)} messages from checkpoint]')
|
|
802
810
|
try:
|
|
803
|
-
|
|
811
|
+
if ui_mode == 'web':
|
|
812
|
+
try:
|
|
813
|
+
from .web import run_web
|
|
814
|
+
except ImportError:
|
|
815
|
+
print('[warning] starlette/uvicorn not installed — falling back to bare.\n Install web deps with: pip install mlx-code[all]')
|
|
816
|
+
engine = CommandEngine()
|
|
817
|
+
main_tab = TabModel(agent, title='main', is_main=True)
|
|
818
|
+
engine.tabs = [main_tab]
|
|
819
|
+
asyncio.run(repl(engine, init_prompt=init_prompt, ui_mode='bare'))
|
|
820
|
+
else:
|
|
821
|
+
run_web(agent=agent, init_prompt=init_prompt, web_host=web_host, web_port=web_port)
|
|
822
|
+
else:
|
|
823
|
+
engine = CommandEngine()
|
|
824
|
+
main_tab = TabModel(agent, title='main', is_main=True)
|
|
825
|
+
engine.tabs = [main_tab]
|
|
826
|
+
asyncio.run(repl(engine, init_prompt=init_prompt, ui_mode=ui_mode))
|
|
804
827
|
finally:
|
|
805
828
|
if log_fp:
|
|
806
829
|
log_fp.close()
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
print('\n--- Session Exit Summary ---')
|
|
818
|
-
for item in engine.exit_summary:
|
|
819
|
-
title = item['title']
|
|
820
|
-
branch = item['branch'] or '(no branch)'
|
|
821
|
-
marker = ' * <-- exit origin' if item['is_exit_tab'] else ''
|
|
822
|
-
print(f' {title} ({branch}){marker}')
|
|
830
|
+
if 'engine' in locals() and hasattr(engine, 'tabs'):
|
|
831
|
+
cleaned: set[str] = set()
|
|
832
|
+
for tab in engine.tabs:
|
|
833
|
+
gwt_ref = tab.agent.ctx.get('gwt')
|
|
834
|
+
if gwt_ref and getattr(gwt_ref, 'worktree', None) and (gwt_ref.worktree not in cleaned):
|
|
835
|
+
cleaned.add(gwt_ref.worktree)
|
|
836
|
+
try:
|
|
837
|
+
cleanup_worktree(gwt_ref)
|
|
838
|
+
except Exception:
|
|
839
|
+
pass
|
|
823
840
|
|
|
824
841
|
def main():
|
|
825
842
|
import argparse
|