aicodinggym-cli 0.4.0__tar.gz → 0.5.1__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aicodinggym-cli
3
- Version: 0.4.0
3
+ Version: 0.5.1
4
4
  Summary: CLI tool for AI Coding Gym platform
5
5
  Author-email: AICodingGym Team <datasmithlab@gmail.com>
6
6
  License-Expression: MIT
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aicodinggym-cli
3
- Version: 0.4.0
3
+ Version: 0.5.1
4
4
  Summary: CLI tool for AI Coding Gym platform
5
5
  Author-email: AICodingGym Team <datasmithlab@gmail.com>
6
6
  License-Expression: MIT
@@ -1,6 +1,8 @@
1
1
  """HTTP API client for the AI Coding Gym backend at aicodinggym.com."""
2
2
 
3
+ import gzip
3
4
  import os
5
+ from pathlib import Path
4
6
 
5
7
  import requests
6
8
 
@@ -123,15 +125,17 @@ def mlebench_download_file(url: str, dest_path: str, timeout: int = 300) -> None
123
125
  def mlebench_submit_csv(user_id: str, competition_id: str, csv_path: str) -> dict:
124
126
  """Upload a prediction CSV for an MLE-bench competition."""
125
127
  try:
128
+ csv_name = Path(csv_path).name
126
129
  with open(csv_path, "rb") as f:
127
- resp = requests.post(
128
- f"{API_BASE}/competitions/{competition_id}/submit",
129
- data={"user_id": user_id, "competition_id": competition_id},
130
- files={"file": (f.name, f, "text/csv")},
131
- timeout=60,
132
- )
133
- resp.raise_for_status()
134
- return resp.json()
130
+ compressed = gzip.compress(f.read())
131
+ resp = requests.post(
132
+ f"{API_BASE}/competitions/{competition_id}/submit",
133
+ data={"user_id": user_id, "competition_id": competition_id},
134
+ files={"file": (csv_name + ".gz", compressed, "application/gzip")},
135
+ timeout=120,
136
+ )
137
+ resp.raise_for_status()
138
+ return resp.json()
135
139
  except requests.ConnectionError:
136
140
  raise APIError(
137
141
  f"Cannot connect to {API_BASE}.\n"
@@ -22,11 +22,13 @@ CODE REVIEW WORKFLOW:
22
22
  aicodinggym cr submit sentry-0001 -f review.md
23
23
  """
24
24
 
25
+ import json
25
26
  import os
26
27
  import platform
27
28
  import re
28
29
  import subprocess
29
30
  import sys
31
+ import urllib.request
30
32
  from datetime import datetime
31
33
  from pathlib import Path
32
34
 
@@ -78,6 +80,81 @@ def _warn(msg: str) -> None:
78
80
  click.echo(f"Warning: {msg}", err=True)
79
81
 
80
82
 
83
+ _GYM_ENV_API = "https://api.github.com/repos/AICodingGym/gym-environment/contents"
84
+ _GYM_ENV_SKIP = {"README.md"}
85
+
86
+
87
+ def _install_gym_environment(dest: Path) -> None:
88
+ """Download gym-environment files into dest and add them to .gitignore."""
89
+ try:
90
+ req = urllib.request.Request(_GYM_ENV_API, headers={"Accept": "application/vnd.github.v3+json"})
91
+ with urllib.request.urlopen(req, timeout=15) as resp:
92
+ entries = json.loads(resp.read())
93
+ except Exception as e:
94
+ _warn(f"Could not fetch gym-environment file list: {e}")
95
+ return
96
+
97
+ downloaded: list[str] = []
98
+
99
+ for entry in entries:
100
+ name = entry.get("name", "")
101
+ if name in _GYM_ENV_SKIP:
102
+ continue
103
+ etype = entry.get("type")
104
+
105
+ if etype == "file":
106
+ url = entry.get("download_url")
107
+ if not url:
108
+ continue
109
+ try:
110
+ with urllib.request.urlopen(url, timeout=15) as r:
111
+ (dest / name).write_bytes(r.read())
112
+ downloaded.append(name)
113
+ except Exception as e:
114
+ _warn(f"Failed to download {name}: {e}")
115
+
116
+ elif etype == "dir":
117
+ # Fetch subdirectory contents recursively (one level deep)
118
+ try:
119
+ sub_req = urllib.request.Request(
120
+ f"{_GYM_ENV_API}/{name}",
121
+ headers={"Accept": "application/vnd.github.v3+json"},
122
+ )
123
+ with urllib.request.urlopen(sub_req, timeout=15) as r:
124
+ sub_entries = json.loads(r.read())
125
+ except Exception as e:
126
+ _warn(f"Failed to list directory {name}: {e}")
127
+ continue
128
+
129
+ sub_dir = dest / name
130
+ sub_dir.mkdir(parents=True, exist_ok=True)
131
+ for sub in sub_entries:
132
+ sub_name = sub.get("name", "")
133
+ sub_url = sub.get("download_url")
134
+ if sub.get("type") != "file" or not sub_url:
135
+ continue
136
+ try:
137
+ with urllib.request.urlopen(sub_url, timeout=15) as r:
138
+ (sub_dir / sub_name).write_bytes(r.read())
139
+ except Exception as e:
140
+ _warn(f"Failed to download {name}/{sub_name}: {e}")
141
+ downloaded.append(name)
142
+
143
+ if not downloaded:
144
+ return
145
+
146
+ # Append to .gitignore
147
+ gitignore = dest / ".gitignore"
148
+ existing = gitignore.read_text(encoding="utf-8") if gitignore.exists() else ""
149
+ existing_lines = set(existing.splitlines())
150
+ new_entries = [f for f in downloaded if f not in existing_lines and f"/{f}" not in existing_lines]
151
+ if new_entries:
152
+ block = "\n# gym-environment\n" + "\n".join(new_entries) + "\n"
153
+ with open(gitignore, "a", encoding="utf-8", newline="\n") as fh:
154
+ fh.write(block)
155
+
156
+
157
+
81
158
  def _resolve_user_id(config: dict, user_id: str | None) -> str:
82
159
  """Resolve user_id from argument or config, with helpful error."""
83
160
  if user_id:
@@ -334,6 +411,8 @@ def configure(user_id: str, workspace_dir: str | None):
334
411
  }
335
412
  save_config(config)
336
413
 
414
+ _install_gym_environment(Path(resolved_workspace))
415
+
337
416
  click.echo(
338
417
  f"\nConfiguration saved successfully!\n"
339
418
  f"\n"
@@ -449,6 +528,8 @@ def swe_fetch(problem_id: str, user_id: str | None, workspace_dir: str | None):
449
528
  if not success:
450
529
  _error(msg)
451
530
 
531
+ _install_gym_environment(workspace / problem_id)
532
+
452
533
  click.echo(
453
534
  f"\nSuccessfully fetched problem: {problem_id}\n"
454
535
  f"\n"
@@ -940,6 +1021,8 @@ def cr_fetch(problem_id: str, user_id: str | None, workspace_dir: str | None):
940
1021
  if not success:
941
1022
  _error(msg)
942
1023
 
1024
+ _install_gym_environment(workspace / problem_id)
1025
+
943
1026
  problem_dir = workspace / problem_id
944
1027
 
945
1028
  # Generate diff.patch
@@ -1099,6 +1182,8 @@ def mle_download(competition_id: str, user_id: str | None, workspace_dir: str |
1099
1182
  except APIError as e:
1100
1183
  _error(str(e))
1101
1184
 
1185
+ _install_gym_environment(workspace / competition_id)
1186
+
1102
1187
  click.echo(
1103
1188
  f"\nDataset downloaded to: {dest_path}\n"
1104
1189
  f"\nNext step: train your model and submit predictions with:\n"
@@ -236,8 +236,12 @@ def add_commit_push(problem_dir: str, branch: str, key_path: Path,
236
236
  """
237
237
  pdir = Path(problem_dir)
238
238
 
239
- # Stage all changes except .github
240
- result = run_git_command(["git", "add", "-A", "--", ".", ":(exclude).github"], str(pdir))
239
+ # Stage all changes except dotfiles/dotdirs and markdown files
240
+ result = run_git_command([
241
+ "git", "add", "-A", "--", ".",
242
+ ":(exclude).*",
243
+ ":(exclude)*.md",
244
+ ], str(pdir))
241
245
  if result.returncode != 0:
242
246
  return False, f"Git add failed:\n{result.stderr}", ""
243
247
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "aicodinggym-cli"
3
- version = "0.4.0"
3
+ version = "0.5.1"
4
4
  description = "CLI tool for AI Coding Gym platform"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"