@mcptoolshop/backpropagate 1.2.0 → 1.4.0

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,204 +1,55 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
3
 
4
- const { spawnSync } = require("child_process");
5
- const path = require("path");
6
- const fs = require("fs");
7
- const os = require("os");
8
-
9
4
  // ---------------------------------------------------------------------------
10
- // Linux: bootstrap a private venv and run backpropagate from PyPI.
5
+ // npm distribution of backpropagate is deprecated as of v1.3.
11
6
  //
12
- // PyTorch's libtorch_cpu.so is ~1.5 GB on x86_64 Linux. A PyInstaller
13
- // --onefile binary lands at 4.16 GB 2x GitHub's release asset limit.
14
- // macOS/Windows don't hit this because Accelerate is system-provided and
15
- // Windows torch is smaller.
7
+ // History: v1.0–v1.2 shipped PyInstaller binaries from a GitHub Release,
8
+ // pulled via @mcptoolshop/npm-launcher. Linux bootstrapped a managed venv
9
+ // instead because libtorch_cpu.so blew past GitHub's 2GB release-asset cap.
10
+ // The binary build pipeline failed three consecutive times in v1.2.0 and the
11
+ // release tag has zero attached assets — the launcher would 404 on download.
16
12
  //
17
- // Instead of shipping a broken giant binary, we bootstrap a managed venv
18
- // on first run and exec the pip-installed CLI from there.
19
- // ---------------------------------------------------------------------------
20
-
21
- const TOOL = "backpropagate";
22
- const VERSION = "1.2.0";
23
-
24
- if (process.platform === "linux") {
25
- // XDG-compliant install root
26
- const dataHome = process.env.XDG_DATA_HOME
27
- || path.join(os.homedir(), ".local", "share");
28
- const installRoot = process.env.BACKPROPAGATE_BOOTSTRAP_ROOT
29
- || path.join(dataHome, TOOL);
30
- const venvDir = path.join(installRoot, "venv");
31
- const metaPath = path.join(installRoot, "install.json");
32
- const venvBin = path.join(venvDir, "bin", TOOL);
33
- const venvPython = path.join(venvDir, "bin", "python3");
34
-
35
- // -- helpers --------------------------------------------------------------
36
-
37
- function findPython() {
38
- // Prefer python3, fall back to python (if it's 3.x)
39
- for (const cmd of ["python3", "python"]) {
40
- const r = spawnSync(cmd, ["--version"], {
41
- encoding: "utf8",
42
- stdio: ["ignore", "pipe", "pipe"],
43
- });
44
- if (r.status === 0) {
45
- const ver = (r.stdout || r.stderr || "").trim();
46
- const match = ver.match(/Python\s+(\d+)\.(\d+)/);
47
- if (match && parseInt(match[1], 10) >= 3 && parseInt(match[2], 10) >= 10) {
48
- return cmd;
49
- }
50
- }
51
- }
52
- return null;
53
- }
54
-
55
- function readMeta() {
56
- try {
57
- return JSON.parse(fs.readFileSync(metaPath, "utf8"));
58
- } catch {
59
- return null;
60
- }
61
- }
62
-
63
- function writeMeta(obj) {
64
- fs.mkdirSync(installRoot, { recursive: true });
65
- fs.writeFileSync(metaPath, JSON.stringify(obj, null, 2) + "\n");
66
- }
67
-
68
- function fail(message, hint) {
69
- process.stderr.write(`\n${TOOL}: ${message}\n`);
70
- if (hint) process.stderr.write(`\n${hint}\n`);
71
- process.stderr.write("\n");
72
- process.exit(1);
73
- }
74
-
75
- // -- bootstrap ------------------------------------------------------------
76
-
77
- function bootstrap() {
78
- const forceReinstall = process.env.BACKPROPAGATE_FORCE_REINSTALL === "1";
79
- const meta = readMeta();
80
-
81
- const versionMatch = meta && meta.version === VERSION;
82
- const binaryPresent = fs.existsSync(venvBin);
83
-
84
- if (versionMatch && binaryPresent && !forceReinstall) {
85
- return; // fast path — venv exists, version matches, no forced reinstall
86
- }
87
-
88
- // Decide what to tell the user
89
- if (forceReinstall) {
90
- process.stderr.write(`Forced reinstall requested (BACKPROPAGATE_FORCE_REINSTALL=1).\n`);
91
- } else if (meta && !versionMatch) {
92
- process.stderr.write(
93
- `Updating ${TOOL}: ${meta.version} -> ${VERSION}\n`
94
- );
95
- } else if (meta && !binaryPresent) {
96
- process.stderr.write(
97
- `Repairing ${TOOL}: binary missing, reinstalling ${VERSION}...\n`
98
- );
99
- }
100
-
101
- // Find system Python
102
- const python = findPython();
103
- if (!python) {
104
- fail(
105
- "Python 3.10+ is required but not found.",
106
- "Install Python and try again:\n" +
107
- " Ubuntu/Debian: sudo apt install python3 python3-venv\n" +
108
- " Fedora/RHEL: sudo dnf install python3\n" +
109
- " Arch: sudo pacman -S python\n" +
110
- " Or use pyenv: https://github.com/pyenv/pyenv"
111
- );
112
- }
113
-
114
- // Recreate venv on force-reinstall (nuke corrupted state)
115
- if (forceReinstall && fs.existsSync(venvDir)) {
116
- process.stderr.write("Removing existing venv...\n");
117
- fs.rmSync(venvDir, { recursive: true, force: true });
118
- }
119
-
120
- // Create venv if missing
121
- if (!fs.existsSync(venvPython)) {
122
- if (!meta) {
123
- process.stderr.write(
124
- `First run on Linux: setting up local Python environment for ${TOOL}...\n`
125
- );
126
- }
127
- fs.mkdirSync(installRoot, { recursive: true });
128
- const venvResult = spawnSync(python, ["-m", "venv", venvDir], {
129
- stdio: "inherit",
130
- });
131
- if (venvResult.status !== 0) {
132
- fail(
133
- "Failed to create Python virtual environment.",
134
- "The venv module may be missing. Try:\n" +
135
- " Ubuntu/Debian: sudo apt install python3-venv\n" +
136
- " Fedora/RHEL: sudo dnf install python3-libs"
137
- );
138
- }
139
- }
140
-
141
- // Install or upgrade backpropagate
142
- // --force-reinstall needed for repair (binary missing but pip metadata intact)
143
- // and force-reinstall (nuked venv rebuilt). Without it, pip sees the same
144
- // version in metadata and skips recreating the entrypoint script.
145
- const needsForce = !binaryPresent || forceReinstall;
146
- const pipArgs = ["-m", "pip", "install", "--quiet", "--upgrade"];
147
- if (needsForce) pipArgs.push("--force-reinstall");
148
- pipArgs.push(`${TOOL}==${VERSION}`);
149
-
150
- process.stderr.write(`Installing ${TOOL} ${VERSION}${needsForce ? " (force)" : ""}...\n`);
151
- const pipResult = spawnSync(venvPython, pipArgs, { stdio: "inherit" });
152
- if (pipResult.status !== 0) {
153
- fail(
154
- `pip install failed (exit ${pipResult.status}).`,
155
- "Check your network connection and try again.\n" +
156
- "You can also install manually:\n" +
157
- ` pip install ${TOOL}==${VERSION}`
158
- );
159
- }
160
-
161
- // Verify the binary actually exists after install
162
- if (!fs.existsSync(venvBin)) {
163
- fail(
164
- `Installation completed but ${TOOL} binary not found at expected path.`,
165
- `Expected: ${venvBin}\n` +
166
- "Try installing manually:\n" +
167
- ` pipx install ${TOOL}`
168
- );
169
- }
170
-
171
- // Record metadata
172
- writeMeta({
173
- version: VERSION,
174
- installedAt: new Date().toISOString(),
175
- python,
176
- venvDir,
177
- });
178
-
179
- process.stderr.write("Ready.\n");
180
- }
181
-
182
- // -- exec -----------------------------------------------------------------
183
-
184
- bootstrap();
185
- const result = spawnSync(venvBin, process.argv.slice(2), { stdio: "inherit" });
186
- if (result.error) {
187
- fail(`Failed to execute ${TOOL}: ${result.error.message}`);
188
- }
189
- process.exit(result.status ?? 1);
190
- }
191
-
192
- // ---------------------------------------------------------------------------
193
- // macOS + Windows: download and launch prebuilt binary via npm-launcher
13
+ // Rather than ship a broken installer, the npm shim now prints install
14
+ // guidance for the supported channels. The package stays published so this
15
+ // message reaches operators who still have `npm install -g backpropagate`
16
+ // in their tooling.
17
+ //
18
+ // Tracked: D2 SPLIT in the v1.3 brief. Wave 1 landed the friendly-error
19
+ // hotfix; Wave 3.5 deleted .github/workflows/release-binaries.yml; Wave 6a
20
+ // removed the PyInstaller .spec files at the repo root and added the v1.2.x
21
+ // v1.3 handbook migration page that walks operators from the
22
+ // pre-deprecation `npm install -g backpropagate` install line to the
23
+ // supported channels. The migration is complete in v1.3.
194
24
  // ---------------------------------------------------------------------------
195
25
 
196
- process.env.MCPTOOLSHOP_LAUNCH_CONFIG = JSON.stringify({
197
- toolName: TOOL,
198
- owner: "mcp-tool-shop-org",
199
- repo: "backpropagate",
200
- version: VERSION,
201
- tag: `v${VERSION}`,
202
- });
203
-
204
- require("@mcptoolshop/npm-launcher/bin/mcptoolshop-launch.js");
26
+ // BRIDGE-B (Stage C humanization): the shim's WHOLE job is the friendly-error
27
+ // path. Three rules the message has to satisfy:
28
+ // 1. Name the next step (every error names the next step).
29
+ // 2. Make the install commands copy-paste-runnable on the operator's host
30
+ // (no shell quoting that fails on cmd.exe, no `sudo` prefix that
31
+ // misleads on Windows).
32
+ // 3. Stay calibrated — the v1.2 PyInstaller-bin build failed 3 times so
33
+ // v1.3 redirected operators to PyPI / pipx / uv; the message names the
34
+ // channels in preference order (isolated > shared > root-installable).
35
+ process.stderr.write(
36
+ "npm distribution of backpropagate is deprecated as of v1.3.\n" +
37
+ "\n" +
38
+ "Next step — install from PyPI via one of these channels (pick one):\n" +
39
+ " pipx install backpropagate # recommended on macOS/Linux (isolated venv, on PATH)\n" +
40
+ " uv tool install backpropagate # recommended on Windows (uv handles venv + PATH)\n" +
41
+ " pip install backpropagate # plain pip (use inside a venv)\n" +
42
+ "\n" +
43
+ "Verify the install: backprop --version\n" +
44
+ "\n" +
45
+ "Optional extras (Reflex UI, GGUF export, monitoring) — pick one bundle:\n" +
46
+ " pipx install 'backpropagate[standard]' # unsloth + ui (recommended)\n" +
47
+ " pipx install 'backpropagate[full]' # everything\n" +
48
+ " pipx install 'backpropagate[ui]' # just the Reflex web UI\n" +
49
+ "\n" +
50
+ "Getting started + extras documentation:\n" +
51
+ " https://mcp-tool-shop-org.github.io/backpropagate/handbook/getting-started/\n" +
52
+ "Source + issues:\n" +
53
+ " https://github.com/mcp-tool-shop-org/backpropagate\n"
54
+ );
55
+ process.exit(2);
package/package.json CHANGED
@@ -1,13 +1,10 @@
1
1
  {
2
2
  "name": "@mcptoolshop/backpropagate",
3
- "version": "1.2.0",
4
- "description": "Headless LLM fine-tuning CLI with smart defaults train, export, serve. Reflex web UI (auth-gated), HF Hub push, resume-from-checkpoint, run history, model cards, multi-run SLAO. v1.2.0: auth-bypass closed + truth-in-advertising sweep.",
3
+ "version": "1.4.0",
4
+ "description": "Deprecated npm distribution shim for backpropagateprints install guidance for pipx/uv tool/pip. See https://github.com/mcp-tool-shop-org/backpropagate",
5
5
  "type": "commonjs",
6
6
  "license": "MIT",
7
7
  "engines": { "node": ">=20" },
8
- "dependencies": {
9
- "@mcptoolshop/npm-launcher": "^1.0.0"
10
- },
11
8
  "bin": {
12
9
  "backpropagate": "bin/backpropagate.js"
13
10
  },