modforge-cli 0.1.9.2__tar.gz → 0.2.0__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: modforge-cli
3
- Version: 0.1.9.2
3
+ Version: 0.2.0
4
4
  Summary: ModForge-CLI — a Modrinth-based Minecraft modpack builder
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "modforge-cli"
3
- version = "0.1.9.2"
3
+ version = "0.2.0"
4
4
  description = "ModForge-CLI — a Modrinth-based Minecraft modpack builder"
5
5
  authors = [{ name = "Frank1o3", email = "jahdy1o3@gmail.com" }]
6
6
  license = { text = "MIT" }
@@ -1,5 +1,5 @@
1
1
  """
2
2
  Auto-generated file. DO NOT EDIT.
3
3
  """
4
- __version__ = "0.1.9.2"
4
+ __version__ = "0.2.0"
5
5
  __author__ = "Frank1o3"
@@ -46,7 +46,7 @@ app = typer.Typer(
46
46
  console = Console()
47
47
 
48
48
  # Configuration
49
- FABRIC_LOADER_VERSION = "0.16.9"
49
+ FABRIC_LOADER_VERSION = "0.18.4"
50
50
  CONFIG_PATH = Path.home() / ".config" / "ModForge-CLI"
51
51
  REGISTRY_PATH = CONFIG_PATH / "registry.json"
52
52
  MODRINTH_API = CONFIG_PATH / "modrinth_api.json"
@@ -54,6 +54,7 @@ POLICY_PATH = CONFIG_PATH / "policy.json"
54
54
 
55
55
  # Use versioned URLs to prevent breaking changes
56
56
  GITHUB_RAW = "https://raw.githubusercontent.com/Frank1o3/ModForge-CLI"
57
+ VERSION_TAG = "v0.1.8" # Update this with each release
57
58
 
58
59
  FABRIC_INSTALLER_URL = (
59
60
  "https://maven.fabricmc.net/net/fabricmc/fabric-installer/1.1.1/fabric-installer-1.1.1.jar"
@@ -62,8 +63,8 @@ FABRIC_INSTALLER_SHA256 = (
62
63
  "8fa465768bd7fc452e08c3a1e5c8a6b4b5f6a4e64bc7def47f89d8d3a6f4e7b8" # Replace with actual hash
63
64
  )
64
65
 
65
- DEFAULT_MODRINTH_API_URL = f"{GITHUB_RAW}/{__version__}/configs/modrinth_api.json"
66
- DEFAULT_POLICY_URL = f"{GITHUB_RAW}/{__version__}/configs/policy.json"
66
+ DEFAULT_MODRINTH_API_URL = f"{GITHUB_RAW}/{VERSION_TAG}/configs/modrinth_api.json"
67
+ DEFAULT_POLICY_URL = f"{GITHUB_RAW}/{VERSION_TAG}/configs/policy.json"
67
68
 
68
69
  # Setup crash logging
69
70
  LOG_DIR = setup_crash_logging()
@@ -113,6 +114,7 @@ def main_callback(
113
114
 
114
115
  if verbose:
115
116
  # Enable verbose logging
117
+
116
118
  logging.basicConfig(
117
119
  level=logging.DEBUG,
118
120
  format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
@@ -175,13 +177,22 @@ def setup(
175
177
  (pack_dir / "ModForge-CLI.json").write_text(manifest.model_dump_json(indent=4))
176
178
 
177
179
  # Create Modrinth index
180
+ # Map loader names to their dependency keys
181
+ loader_key_map = {
182
+ "fabric": "fabric-loader",
183
+ "quilt": "quilt-loader",
184
+ "forge": "forge",
185
+ "neoforge": "neoforge",
186
+ }
187
+ loader_key = loader_key_map.get(loader.lower(), loader.lower())
188
+
178
189
  index_data = {
179
190
  "formatVersion": 1,
180
191
  "game": "minecraft",
181
192
  "versionId": "1.0.0",
182
193
  "name": name,
183
- "dependencies": {"minecraft": mc, loader: "*"},
184
- "files": [],
194
+ "dependencies": {"minecraft": mc, loader_key: loader_version},
195
+ "files": [], # Only for overrides, not mods
185
196
  }
186
197
  (pack_dir / "modrinth.index.json").write_text(json.dumps(index_data, indent=2))
187
198
 
@@ -265,7 +276,7 @@ def resolve(pack_name: str | None = None) -> None:
265
276
  policy=policy, api=api, mc_version=manifest.minecraft, loader=manifest.loader
266
277
  )
267
278
 
268
- async def do_resolve() -> set[str]:
279
+ async def do_resolve():
269
280
  async with await get_api_session() as session:
270
281
  return await resolver.resolve(manifest.mods, session)
271
282
 
@@ -356,6 +367,7 @@ def export(pack_name: str | None = None) -> None:
356
367
 
357
368
  if not installer.exists():
358
369
  console.print("[yellow]Downloading Fabric installer...[/yellow]")
370
+
359
371
 
360
372
  urllib.request.urlretrieve(FABRIC_INSTALLER_URL, installer)
361
373
 
@@ -375,16 +387,11 @@ def export(pack_name: str | None = None) -> None:
375
387
  loader_version=loader_version,
376
388
  game_dir=pack_path,
377
389
  )
390
+ console.print(f"[green]✓ Fabric {loader_version} installed[/green]")
378
391
  except RuntimeError as e:
379
392
  console.print(f"[red]{e}[/red]")
380
393
  raise typer.Exit(1) from e
381
394
 
382
- # Update index
383
- index_file = pack_path / "modrinth.index.json"
384
- index = json.loads(index_file.read_text())
385
- index["dependencies"]["fabric-loader"] = loader_version
386
- index_file.write_text(json.dumps(index, indent=2))
387
-
388
395
  installer.unlink(missing_ok=True)
389
396
 
390
397
  # Create .mrpack
@@ -485,6 +492,7 @@ def doctor() -> None:
485
492
 
486
493
  # Check Java
487
494
  try:
495
+
488
496
  result = subprocess.run(["java", "-version"], capture_output=True, text=True, check=True)
489
497
  console.print("[green]✓[/green] Java installed")
490
498
  except (FileNotFoundError, subprocess.CalledProcessError):
@@ -74,6 +74,13 @@ class ModDownloader:
74
74
  return compatible[0]
75
75
 
76
76
  async def download_all(self, project_ids: Iterable[str]) -> None:
77
+ """
78
+ Download all mods and update modrinth.index.json dependencies.
79
+
80
+ Note: Modrinth launchers auto-download mods based on dependencies.
81
+ We download to mods/ folder for local use, but the index only needs
82
+ the version IDs in dependencies, not file paths.
83
+ """
77
84
  tasks = [self._download_project(pid) for pid in project_ids]
78
85
 
79
86
  with Progress(
@@ -88,8 +95,35 @@ class ModDownloader:
88
95
  await coro
89
96
  progress.advance(task_id)
90
97
 
98
+ # Update dependencies section with correct loader version
99
+ self._update_dependencies()
91
100
  self.index_file.write_text(json.dumps(self.index, indent=2))
92
101
 
102
+ def _update_dependencies(self) -> None:
103
+ """
104
+ Ensure dependencies section has correct MC version and loader.
105
+ This is what launchers use to setup the game.
106
+ """
107
+ if "dependencies" not in self.index:
108
+ self.index["dependencies"] = {}
109
+
110
+ # Set Minecraft version
111
+ self.index["dependencies"]["minecraft"] = self.mc_version
112
+
113
+ # Set loader (fabric-loader, forge, quilt-loader, neoforge)
114
+ loader_key_map = {
115
+ "fabric": "fabric-loader",
116
+ "quilt": "quilt-loader",
117
+ "forge": "forge",
118
+ "neoforge": "neoforge",
119
+ }
120
+
121
+ loader_key = loader_key_map.get(self.loader.lower(), self.loader.lower())
122
+
123
+ # Use "*" to let launcher pick latest compatible version
124
+ # Or you can specify exact version if available
125
+ self.index["dependencies"][loader_key] = "*"
126
+
93
127
  async def _download_project(self, project_id: str) -> None:
94
128
  # 1. Fetch all versions for this project
95
129
  url = self.api.project_versions(project_id)
@@ -134,15 +168,14 @@ class ModDownloader:
134
168
  )
135
169
  return
136
170
 
137
- # 4. Download file
171
+ # 4. Download file to mods/ directory
138
172
  dest = self.output_dir / primary_file["filename"]
139
173
 
140
- # Skip if already downloaded
174
+ # Skip if already downloaded and hash matches
141
175
  if dest.exists():
142
- # Verify existing file hash
143
176
  existing_hash = hashlib.sha1(dest.read_bytes()).hexdigest()
144
177
  if existing_hash == primary_file["hashes"]["sha1"]:
145
- console.print(f"[dim]Skipping {primary_file['filename']} (already exists)[/dim]")
178
+ console.print(f"[dim] {primary_file['filename']} (cached)[/dim]")
146
179
  return
147
180
  else:
148
181
  console.print(
@@ -172,17 +205,7 @@ class ModDownloader:
172
205
  f" Got: {sha1}"
173
206
  )
174
207
 
175
- # 6. Register in index
176
- self.index["files"].append(
177
- {
178
- "path": f"mods/{primary_file['filename']}",
179
- "hashes": {"sha1": sha1},
180
- "downloads": [primary_file["url"]],
181
- "fileSize": primary_file["size"],
182
- }
183
- )
184
-
185
208
  console.print(
186
209
  f"[green]✓[/green] {primary_file['filename']} "
187
- f"[dim](MC {self.mc_version}, {self.loader})[/dim]"
210
+ f"[dim](v{version.get('version_number')}, {self.loader})[/dim]"
188
211
  )
File without changes
File without changes