drift-ml 0.1.15 → 0.2.1

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.
Files changed (3) hide show
  1. package/README.md +27 -53
  2. package/bin/drift.js +26 -65
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -1,86 +1,60 @@
1
- # drift-ml
1
+ # drift
2
2
 
3
- **Drift** by Lakshit Sachdeva — terminal-first, chat-based AutoML. Same engine as the web app. Local-first: the engine runs on your machine; no commands to memorize.
3
+ **Terminal-first, chat-based AutoML.** Open source. No tokens. No auth. Works fully local.
4
4
 
5
5
  ---
6
6
 
7
- ## Exactly what to do
7
+ ## Install
8
8
 
9
- 1. **Install drift** (pipx recommended — works standalone)
10
- ```bash
11
- pipx install drift-ml
12
- ```
13
- Or: `npm install -g drift-ml` (requires `pipx install drift-ml` for the CLI).
14
-
15
- 2. **Run drift**
16
- ```bash
17
- drift
18
- ```
19
- On first run, the CLI detects your OS and architecture, downloads the correct engine binary into `~/.drift/bin/`, and starts the engine in the background. You’ll see a short welcome and instructions in the terminal.
20
-
21
- 3. **Use a local LLM**
22
- Training and planning use an LLM. You need one of:
23
- - **Gemini CLI** — install it and set `GEMINI_API_KEY` or have `gemini` on your PATH.
24
- - **Ollama** — run `ollama run llama2` (or another model).
25
- - Another local LLM the engine supports.
26
-
27
- 4. **Chat**
28
- - `load path/to/data.csv`
29
- - `predict price` (or any column)
30
- - `try something stronger`
31
- - `why is accuracy capped`
32
- - `quit` to exit.
33
-
34
- That’s it. The engine runs locally. The web app (if you use it) can be hosted on Vercel; the engine stays on your machine.
35
-
36
- ---
37
-
38
- ## What is drift?
9
+ ```bash
10
+ pipx install drift-ml
11
+ ```
39
12
 
40
- - **Local-first** The engine runs on your machine. Training and planning stay local; you never send data to our servers.
41
- - **Terminal-first, chat-based** — Same engine as the web app. No commands to memorize; chat in natural language.
42
- - **Engine** — On first run the CLI downloads and starts the engine from `~/.drift/bin/`. Or set `DRIFT_BACKEND_URL` to a running engine URL.
13
+ Or with npm (also requires pipx for the CLI):
43
14
 
44
- **Custom / private repo:** Engine binaries are hosted at [lakshitsachdeva/drift](https://github.com/lakshitsachdeva/drift) (public). For a private fork, set `DRIFT_GITHUB_TOKEN` with a token that has repo read access.
15
+ ```bash
16
+ pipx install drift-ml
17
+ npm install -g drift-ml
18
+ ```
45
19
 
46
20
  ---
47
21
 
48
- ## Install (details)
22
+ ## Run
49
23
 
50
24
  ```bash
51
- npm install -g drift-ml
52
25
  drift
53
26
  ```
54
27
 
55
- The `drift` command installs or upgrades the chat CLI (Python) and runs it. You get the welcome and instructions every time.
28
+ That's it. On first run, drift downloads and starts the engine automatically. No backend setup. No config.
56
29
 
57
- ### Alternative: pipx (Python only — macOS, Linux, Windows)
30
+ ---
58
31
 
59
- ```bash
60
- pipx install drift-ml
61
- drift
62
- ```
32
+ ## How it works
63
33
 
64
- **Update (pipx):**
65
- ```bash
66
- pipx upgrade drift-ml
67
- ```
68
- (PowerShell on Windows: same command.)
34
+ - **Local-first** — Engine runs on your machine. Data never leaves.
35
+ - **Chat-based** — `load data.csv`, `predict price`, `try something stronger`
36
+ - **Auto-start** — Engine downloads and starts in the background. You never touch it.
37
+ - **No tokens** — No API keys for drift. (You need an LLM for training: Ollama, Gemini CLI, etc.)
69
38
 
70
39
  ---
71
40
 
72
- ## Example usage
41
+ ## Example
73
42
 
74
43
  ```text
75
44
  drift › load iris.csv
76
- drift › predict sepal.length
45
+ drift › predict variety
77
46
  drift › try something stronger
78
- drift › why is accuracy capped
79
47
  drift › quit
80
48
  ```
81
49
 
82
50
  ---
83
51
 
52
+ ## Philosophy
53
+
54
+ drift should feel like `git`, `docker`, `brew` — a tool you trust immediately. Zero friction. Open source.
55
+
56
+ ---
57
+
84
58
  ## License
85
59
 
86
60
  MIT
package/bin/drift.js CHANGED
@@ -1,11 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  //
3
- // REMOVED: Any pip/pipx/python -m pip install or upgrade logic.
4
- // WHY: PEP 668 and user envs; we must not modify Python. User installs CLI via pipx once.
5
- //
6
- // FINAL FLOW: (1) If no DRIFT_BACKEND_URL, ensure engine at 127.0.0.1:8000 (download + start if needed).
7
- // (2) Locate Python drift ONLY in ~/.local/bin (macOS/Linux) or %USERPROFILE%\.local\bin (Windows).
8
- // (3) Spawn that binary with DRIFT_BACKEND_URL set; never run drift.cmd/drift.ps1/drift.js (self).
3
+ // drift terminal-first AutoML. Engine auto-starts locally.
4
+ // No tokens. No auth. No backend setup.
9
5
  //
10
6
 
11
7
  const { spawnSync, spawn } = require("child_process");
@@ -16,16 +12,13 @@ const http = require("http");
16
12
 
17
13
  const isWindows = process.platform === "win32";
18
14
  const ENGINE_PORT = process.env.DRIFT_ENGINE_PORT || "8000";
19
- // Pinned tag: draft releases are invisible to /releases/latest.
20
- const ENGINE_TAG = "v0.1.3";
21
- const GITHUB_REPO = "lakshitsachdeva/drift";
22
- const ENGINE_BASE_URL = process.env.DRIFT_ENGINE_BASE_URL || `https://github.com/${GITHUB_REPO}/releases/download/${ENGINE_TAG}`;
23
- const GITHUB_API_RELEASE = `https://api.github.com/repos/${GITHUB_REPO}/releases/tags/${ENGINE_TAG}`;
24
- const GITHUB_TOKEN = process.env.DRIFT_GITHUB_TOKEN || process.env.GITHUB_TOKEN;
15
+ const GITHUB_REPO = "lakshitsachdeva/drift"; // Engine binaries
16
+ const ENGINE_TAG = "v0.2.0"; // Pinned — direct URL, no API, no rate limits
17
+ const ENGINE_BASE_URL = `https://github.com/${GITHUB_REPO}/releases/download/${ENGINE_TAG}`;
25
18
  const HEALTH_URL = `http://127.0.0.1:${ENGINE_PORT}/health`;
26
19
  const HEALTH_TIMEOUT_MS = 2000;
27
20
  const HEALTH_POLL_MS = 500;
28
- const HEALTH_POLL_MAX = 60; // 30 seconds total
21
+ const HEALTH_POLL_MAX = 60;
29
22
  const isMac = process.platform === "darwin";
30
23
 
31
24
  function getPlatformKey() {
@@ -66,55 +59,32 @@ function fetchOk(url) {
66
59
  });
67
60
  }
68
61
 
69
- const API_HEADERS = {
70
- "User-Agent": "Drift-Engine-Launcher/1.0",
71
- Accept: "application/vnd.github+json",
72
- ...(GITHUB_TOKEN && { Authorization: `Bearer ${GITHUB_TOKEN}` }),
73
- };
74
- const DOWNLOAD_HEADERS = {
75
- "User-Agent": "Drift-Engine-Launcher/1.0",
76
- Accept: "application/octet-stream",
77
- ...(GITHUB_TOKEN && { Authorization: `Bearer ${GITHUB_TOKEN}` }),
78
- };
62
+ function getAssetUrl(assetName) {
63
+ const baseUrl = process.env.DRIFT_ENGINE_BASE_URL;
64
+ if (baseUrl) {
65
+ return `${baseUrl.replace(/\/$/, "")}/${assetName}`;
66
+ }
67
+ return `${ENGINE_BASE_URL}/${assetName}`;
68
+ }
79
69
 
80
- // Resolve GitHub release asset to API download URL (browser_download_url returns 404 for scripts).
81
- function getGitHubAssetUrl(assetName) {
70
+ function downloadWithCurl(url, destPath) {
82
71
  return new Promise((resolve, reject) => {
83
- const req = https.get(GITHUB_API_RELEASE, { headers: API_HEADERS }, (res) => {
84
- if (res.statusCode === 404) {
85
- reject(new Error(
86
- "Release not found (404). If the repo is private, set DRIFT_GITHUB_TOKEN with a token that has repo read access."
87
- ));
88
- return;
89
- }
90
- if (res.statusCode !== 200) {
91
- reject(new Error(`Release not found: ${res.statusCode}`));
92
- return;
93
- }
94
- let body = "";
95
- res.on("data", (chunk) => { body += chunk; });
96
- res.on("end", () => {
97
- try {
98
- const data = JSON.parse(body);
99
- const asset = (data.assets || []).find((a) => a.name === assetName);
100
- if (!asset || !asset.url) {
101
- reject(new Error(`Asset not found: ${assetName}`));
102
- return;
103
- }
104
- resolve(asset.url);
105
- } catch (e) {
106
- reject(e);
107
- }
108
- });
72
+ const result = spawnSync("curl", ["-fsSL", "-o", destPath, url], {
73
+ stdio: "pipe",
74
+ timeout: 120000,
109
75
  });
110
- req.on("error", reject);
76
+ if (result.status !== 0) {
77
+ reject(new Error("Download failed"));
78
+ return;
79
+ }
80
+ resolve();
111
81
  });
112
82
  }
113
83
 
114
84
  function downloadFile(url, destPath) {
115
85
  return new Promise((resolve, reject) => {
116
86
  const client = url.startsWith("https") ? https : http;
117
- const req = client.get(url, { headers: DOWNLOAD_HEADERS }, (res) => {
87
+ const req = client.get(url, { headers: { "User-Agent": "Drift/1.0" } }, (res) => {
118
88
  const redirect = res.statusCode >= 301 && res.statusCode <= 302 && res.headers.location;
119
89
  if (redirect) {
120
90
  downloadFile(redirect, destPath).then(resolve).catch(reject);
@@ -166,16 +136,12 @@ async function ensureEngine() {
166
136
  const { plat, arch } = getPlatformKey();
167
137
  const ext = isWindows ? ".exe" : "";
168
138
  const asset = `drift-engine-${plat}-${arch}${ext}`;
169
- const isDefaultGitHub = !process.env.DRIFT_ENGINE_BASE_URL;
170
- const url = isDefaultGitHub
171
- ? await getGitHubAssetUrl(asset)
172
- : `${ENGINE_BASE_URL.replace(/\/$/, "")}/${asset}`;
139
+ const url = getAssetUrl(asset);
173
140
  process.stderr.write(`drift: Downloading engine (${asset})...\n`);
174
141
  try {
175
- await downloadFile(url, binPath);
142
+ await downloadWithCurl(url, binPath).catch(() => downloadFile(url, binPath));
176
143
  } catch (e) {
177
144
  console.error("drift: Download failed.", e.message);
178
- console.error("drift: Set DRIFT_ENGINE_BASE_URL or run the engine manually.");
179
145
  return false;
180
146
  }
181
147
  if (!isWindows) {
@@ -187,7 +153,6 @@ async function ensureEngine() {
187
153
  } catch (_) {}
188
154
  }
189
155
  }
190
- // On macOS, always ensure binary is executable and not quarantined before spawn (covers existing binaries).
191
156
  if (isMac && binPath) {
192
157
  try {
193
158
  fs.chmodSync(binPath, 0o755);
@@ -204,7 +169,6 @@ async function ensureEngine() {
204
169
  return waitForEngine();
205
170
  }
206
171
 
207
- // Locate Python drift ONLY in pipx bin dir. Never search PATH (avoids running drift.cmd/drift.ps1/drift.js).
208
172
  function findPythonDrift() {
209
173
  const home = process.env.HOME || process.env.USERPROFILE || "";
210
174
  if (!home) return null;
@@ -230,7 +194,6 @@ async function main() {
230
194
  });
231
195
  if (!started) {
232
196
  console.error("Failed to start drift engine.");
233
- console.error("Please check permissions or download the engine manually.");
234
197
  process.exit(1);
235
198
  }
236
199
  }
@@ -239,9 +202,7 @@ async function main() {
239
202
  const driftPath = findPythonDrift();
240
203
  if (!driftPath) {
241
204
  console.error(`
242
- drift is not installed.
243
-
244
- Install it with:
205
+ drift is not installed. Install it with:
245
206
 
246
207
  pipx install drift-ml
247
208
  `);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "drift-ml",
3
- "version": "0.1.15",
4
- "description": "Drift — terminal-first, chat-based AutoML. Same engine as the web app. On first run: downloads and starts the engine locally (never exposes engine source).",
3
+ "version": "0.2.1",
4
+ "description": "drift — terminal-first, chat-based AutoML. Open source. No tokens. No auth.",
5
5
  "bin": {
6
6
  "drift": "bin/drift.js"
7
7
  },
@@ -9,7 +9,7 @@
9
9
  "engines": {
10
10
  "node": ">=18"
11
11
  },
12
- "keywords": ["drift", "automl", "cli", "ml", "terminal", "local-first"],
12
+ "keywords": ["drift", "automl", "cli", "ml", "terminal", "local-first", "ai", "open-source"],
13
13
  "license": "MIT",
14
14
  "author": "Lakshit Sachdeva",
15
15
  "repository": {