@mriekki/project-forge 4.14.1 → 4.14.2

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.
@@ -6,13 +6,16 @@
6
6
  "asset": "assets/bootstrap-migrations/wsl-setup/setup-wsl.py",
7
7
  "source": {
8
8
  "component": "bootstrap",
9
- "revision": "173203baaf36935d04eb81c89f1d016131a40442",
9
+ "revision": "9f0f7fd4e0e2220250f6fd5b035706a7d15834af",
10
10
  "artifact": "runtime/dev_environment_wsl.py"
11
11
  },
12
- "targetGitBlob": "6731910246fb99887c58b9f3a8a14fec1bf02c01",
13
- "supportedPredecessorGitBlobs": [],
12
+ "targetGitBlob": "883f7bbadd2de4bc0dcb601ee2285f88a0085b52",
13
+ "supportedPredecessorGitBlobs": [
14
+ "6731910246fb99887c58b9f3a8a14fec1bf02c01"
15
+ ],
14
16
  "supportedBootstrapRevisions": [
15
- "0c45eb332a815ad79ea061443f337500b9dc5712"
17
+ "0c45eb332a815ad79ea061443f337500b9dc5712",
18
+ "173203baaf36935d04eb81c89f1d016131a40442"
16
19
  ],
17
20
  "allowMissing": true
18
21
  }
@@ -85,24 +85,79 @@ def ensure_apt_package(package: str) -> None:
85
85
  raise SetupError(f"Unable to install required Ubuntu package: {package}")
86
86
 
87
87
 
88
+ def fnm_install_dir() -> Path:
89
+ xdg_data_home = os.environ.get("XDG_DATA_HOME")
90
+ base = Path(xdg_data_home).expanduser() if xdg_data_home else Path.home() / ".local" / "share"
91
+ return base / "fnm"
92
+
93
+
94
+ def refresh_fnm_path() -> None:
95
+ install_dir = fnm_install_dir()
96
+ fnm_binary = install_dir / "fnm"
97
+ if not fnm_binary.is_file():
98
+ return
99
+ current = os.environ.get("PATH", "")
100
+ prefix = str(install_dir)
101
+ parts = current.split(os.pathsep) if current else []
102
+ if prefix not in parts:
103
+ os.environ["PATH"] = prefix + (os.pathsep + current if current else "")
104
+
105
+
106
+ def ensure_fnm_available(check_only: bool) -> tuple[bool, str, str]:
107
+ refresh_fnm_path()
108
+ path = command_path("fnm")
109
+ if path:
110
+ result = run(["fnm", "--version"])
111
+ detail = "\n".join(filter(None, [(result.stdout or "").strip(), (result.stderr or "").strip()]))
112
+ return result.returncode == 0, detail or path, "PASS" if result.returncode == 0 else "FAILED"
113
+
114
+ if check_only:
115
+ return False, "fnm is missing in WSL", "MISSING"
116
+
117
+ ensure_apt_package("curl")
118
+ ensure_apt_package("unzip")
119
+ install = run(
120
+ ["bash", "-lc", "curl -fsSL https://fnm.vercel.app/install | bash"],
121
+ capture=False,
122
+ )
123
+ if install.returncode != 0:
124
+ return False, "fnm installer failed", "FAILED"
125
+
126
+ refresh_fnm_path()
127
+ path = command_path("fnm")
128
+ if not path:
129
+ return False, f"fnm installer completed but {fnm_install_dir() / 'fnm'} is unavailable", "FAILED"
130
+
131
+ verify = run(["fnm", "--version"])
132
+ detail = "\n".join(filter(None, [(verify.stdout or "").strip(), (verify.stderr or "").strip()]))
133
+ return verify.returncode == 0, detail or path, "PASS" if verify.returncode == 0 else "FAILED"
134
+
135
+
88
136
  def ensure_fnm_node(version: str | None, check_only: bool) -> tuple[bool, str, str]:
89
- if not command_path("fnm"):
90
- return False, "fnm is missing in WSL; install fnm inside the distro before rerunning /setup", "MISSING"
137
+ fnm_ok, fnm_detail, fnm_state = ensure_fnm_available(check_only)
138
+ if not fnm_ok:
139
+ return False, fnm_detail, fnm_state
91
140
  if not version:
92
- return True, "fnm available", "PASS"
141
+ return True, fnm_detail or "fnm available", "PASS"
142
+
93
143
  result = run(["fnm", "exec", f"--using={version}", "--", "node", "--version"])
94
144
  detail = "\n".join(filter(None, [(result.stdout or "").strip(), (result.stderr or "").strip()]))
95
145
  if result.returncode == 0 and version in detail.lstrip("v"):
96
146
  return True, detail, "PASS"
97
147
  if check_only:
98
148
  return False, detail or f"Node {version} is not installed through fnm", "VERSION_MISMATCH"
149
+
99
150
  install = run(["fnm", "install", version], capture=False)
100
151
  if install.returncode != 0:
101
152
  return False, f"fnm failed to install Node {version}", "FAILED"
102
- run(["fnm", "default", version], capture=False)
153
+ default = run(["fnm", "default", version], capture=False)
154
+ if default.returncode != 0:
155
+ return False, f"fnm installed Node {version} but failed to make it the default", "FAILED"
156
+
103
157
  verify = run(["fnm", "exec", f"--using={version}", "--", "node", "--version"])
104
158
  text = (verify.stdout or verify.stderr or "").strip()
105
- return verify.returncode == 0 and version in text.lstrip("v"), text, "PASS" if verify.returncode == 0 else "FAILED"
159
+ ok = verify.returncode == 0 and version in text.lstrip("v")
160
+ return ok, text or f"Node {version} verification failed", "PASS" if ok else "FAILED"
106
161
 
107
162
 
108
163
  def ensure_tool(entry: dict[str, Any], check_only: bool) -> tuple[bool, str, str]:
@@ -110,6 +165,8 @@ def ensure_tool(entry: dict[str, Any], check_only: bool) -> tuple[bool, str, str
110
165
  spec = read_json(CATALOG / f"{tool_id}.json")
111
166
  version = entry.get("version")
112
167
 
168
+ if tool_id == "fnm":
169
+ return ensure_fnm_available(check_only)
113
170
  if tool_id == "node":
114
171
  return ensure_fnm_node(version, check_only)
115
172
 
@@ -130,10 +187,15 @@ def ensure_tool(entry: dict[str, Any], check_only: bool) -> tuple[bool, str, str
130
187
  if check_only:
131
188
  return False, detail, "MISSING" if detail == "missing" else "VERSION_MISMATCH"
132
189
 
190
+ if tool_id == "python":
191
+ ensure_apt_package("python3")
192
+ ensure_apt_package("python-is-python3")
193
+ ok, detail = version_ok(spec, version)
194
+ return ok, detail, "PASS" if ok else "FAILED"
195
+
133
196
  apt_packages = {
134
197
  "git": "git",
135
198
  "github-cli": "gh",
136
- "python": "python3",
137
199
  "sqlite": "sqlite3",
138
200
  "ssh": "openssh-client",
139
201
  "go": "golang-go",
@@ -143,6 +205,16 @@ def ensure_tool(entry: dict[str, Any], check_only: bool) -> tuple[bool, str, str
143
205
  ok, detail = version_ok(spec, version)
144
206
  return ok, detail, "PASS" if ok else "FAILED"
145
207
 
208
+ if tool_id == "dotnet":
209
+ if not version:
210
+ return False, ".NET SDK version is required for automatic WSL installation", "FAILED"
211
+ major = version.split(".", 1)[0]
212
+ if not re.fullmatch(r"\d+", major):
213
+ return False, f"Unsupported .NET SDK version: {version}", "FAILED"
214
+ ensure_apt_package(f"dotnet-sdk-{major}.0")
215
+ ok, detail = version_ok(spec, version)
216
+ return ok, detail, "PASS" if ok else "FAILED"
217
+
146
218
  if tool_id == "vscode":
147
219
  return False, (
148
220
  "VS Code's WSL command bridge is unavailable. Install VS Code on Windows and the "
@@ -153,16 +225,6 @@ def ensure_tool(entry: dict[str, Any], check_only: bool) -> tuple[bool, str, str
153
225
  "Docker is unavailable inside WSL. Install/start Docker Desktop on Windows and enable "
154
226
  "WSL integration for this distro; do not install Docker Engine inside WSL."
155
227
  ), "MISSING"
156
- if tool_id == "fnm":
157
- return False, (
158
- "fnm is required inside WSL for Project-declared Node versions. Install fnm in this "
159
- "distro, then rerun /setup."
160
- ), "MISSING"
161
- if tool_id == "dotnet":
162
- return False, (
163
- f".NET SDK {version or ''} is required inside WSL. Install the matching Microsoft .NET SDK "
164
- "for Ubuntu in this distro, then rerun /setup."
165
- ).strip(), "MISSING" if detail == "missing" else "VERSION_MISMATCH"
166
228
  if tool_id == "java":
167
229
  return False, (
168
230
  f"Java {version or ''} is required inside WSL. Install the matching JDK in this distro, "
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
3
  "package": "@mriekki/project-forge",
4
- "version": "4.14.1",
4
+ "version": "4.14.2",
5
5
  "defaultProfile": "greenfield-project",
6
6
  "profiles": {
7
7
  "greenfield-project": {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
3
  "package": "@mriekki/project-forge",
4
- "version": "4.14.1",
4
+ "version": "4.14.2",
5
5
  "components": {
6
6
  "core": {
7
7
  "revision": "b51cb62bcc9630748168c9fd1900c6109cafb587",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mriekki/project-forge",
3
- "version": "4.14.1",
3
+ "version": "4.14.2",
4
4
  "description": "Public consumer distribution and updater for Project Forge engineering assets.",
5
5
  "type": "module",
6
6
  "bin": {