drift-ml 0.1.1 → 0.1.4
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.
- package/bin/drift.js +62 -155
- package/package.json +1 -1
package/bin/drift.js
CHANGED
|
@@ -1,175 +1,82 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const { spawnSync
|
|
4
|
-
const fs = require("fs");
|
|
3
|
+
const { spawnSync } = require("child_process");
|
|
5
4
|
const path = require("path");
|
|
6
|
-
const
|
|
7
|
-
const http = require("http");
|
|
8
|
-
|
|
9
|
-
const ENGINE_PORT = process.env.DRIFT_ENGINE_PORT || "8000";
|
|
10
|
-
const ENGINE_BASE = process.env.DRIFT_ENGINE_BASE_URL || "https://github.com/lakshitsachdeva/drift/releases/latest/download";
|
|
11
|
-
const HEALTH_URL = `http://127.0.0.1:${ENGINE_PORT}/health`;
|
|
12
|
-
const HEALTH_TIMEOUT_MS = 2000;
|
|
13
|
-
const HEALTH_POLL_MS = 500;
|
|
14
|
-
const HEALTH_POLL_MAX = 60; // 30s
|
|
15
|
-
|
|
16
|
-
function which(cmd) {
|
|
17
|
-
const { status, stdout } = spawnSync("which", [cmd], { encoding: "utf8" });
|
|
18
|
-
return status === 0 ? (stdout || "").trim() : null;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function getPlatformKey() {
|
|
22
|
-
const p = process.platform;
|
|
23
|
-
const a = process.arch;
|
|
24
|
-
const plat = p === "darwin" ? "macos" : p === "win32" ? "windows" : "linux";
|
|
25
|
-
const arch = a === "arm64" || a === "aarch64" ? "arm64" : "x64";
|
|
26
|
-
return { plat, arch };
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function getEngineDir() {
|
|
30
|
-
const home = process.env.HOME || process.env.USERPROFILE || process.env.HOMEPATH;
|
|
31
|
-
if (!home) return null;
|
|
32
|
-
return path.join(home, ".drift", "bin");
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function getEnginePath() {
|
|
36
|
-
const dir = getEngineDir();
|
|
37
|
-
if (!dir) return null;
|
|
38
|
-
const { plat, arch } = getPlatformKey();
|
|
39
|
-
const ext = process.platform === "win32" ? ".exe" : "";
|
|
40
|
-
return path.join(dir, `drift-engine-${plat}-${arch}${ext}`);
|
|
41
|
-
}
|
|
5
|
+
const fs = require("fs");
|
|
42
6
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
resolve(res.statusCode === 200);
|
|
53
|
-
});
|
|
54
|
-
req.on("error", () => resolve(false));
|
|
55
|
-
req.on("timeout", () => { req.destroy(); resolve(false); });
|
|
56
|
-
});
|
|
7
|
+
// Known pipx install locations
|
|
8
|
+
function getPipxBinPaths() {
|
|
9
|
+
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
10
|
+
return [
|
|
11
|
+
path.join(home, ".local", "bin", "drift"),
|
|
12
|
+
"/usr/local/bin/drift",
|
|
13
|
+
];
|
|
57
14
|
}
|
|
58
15
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
16
|
+
// Find Python-based drift (not this Node script)
|
|
17
|
+
function findPythonDrift() {
|
|
18
|
+
// First check pipx standard locations
|
|
19
|
+
for (const p of getPipxBinPaths()) {
|
|
20
|
+
if (fs.existsSync(p)) {
|
|
21
|
+
// Verify it's not a Node script (i.e., not us)
|
|
22
|
+
try {
|
|
23
|
+
const content = fs.readFileSync(p, "utf8").slice(0, 100);
|
|
24
|
+
if (!content.includes("#!/usr/bin/env node")) {
|
|
25
|
+
return p;
|
|
26
|
+
}
|
|
27
|
+
} catch (_) {}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Fallback: search PATH but skip Node scripts
|
|
32
|
+
const pathEnv = process.env.PATH || "";
|
|
33
|
+
const dirs = pathEnv.split(path.delimiter);
|
|
34
|
+
|
|
35
|
+
for (const dir of dirs) {
|
|
36
|
+
const candidate = path.join(dir, "drift");
|
|
37
|
+
if (fs.existsSync(candidate)) {
|
|
38
|
+
try {
|
|
39
|
+
const content = fs.readFileSync(candidate, "utf8").slice(0, 100);
|
|
40
|
+
// Skip if it's a Node script (that's us or another Node launcher)
|
|
41
|
+
if (content.includes("#!/usr/bin/env node")) {
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
return candidate;
|
|
45
|
+
} catch (_) {
|
|
46
|
+
// Binary file or unreadable - might be the real one
|
|
47
|
+
return candidate;
|
|
71
48
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
file.on("finish", () => { file.close(); resolve(); });
|
|
77
|
-
file.on("error", reject);
|
|
78
|
-
});
|
|
79
|
-
req.on("error", reject);
|
|
80
|
-
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return null;
|
|
81
53
|
}
|
|
82
54
|
|
|
83
|
-
function
|
|
84
|
-
|
|
85
|
-
|
|
55
|
+
function main() {
|
|
56
|
+
const driftPath = findPythonDrift();
|
|
57
|
+
|
|
58
|
+
if (!driftPath) {
|
|
59
|
+
console.error(`
|
|
60
|
+
drift is not installed.
|
|
86
61
|
|
|
87
|
-
|
|
88
|
-
return new Promise((resolve) => {
|
|
89
|
-
let n = 0;
|
|
90
|
-
const t = setInterval(() => {
|
|
91
|
-
n++;
|
|
92
|
-
fetchOk(HEALTH_URL).then((ok) => {
|
|
93
|
-
if (ok) { clearInterval(t); resolve(true); }
|
|
94
|
-
else if (n >= HEALTH_POLL_MAX) { clearInterval(t); resolve(false); }
|
|
95
|
-
});
|
|
96
|
-
}, HEALTH_POLL_MS);
|
|
97
|
-
});
|
|
98
|
-
}
|
|
62
|
+
Install it with:
|
|
99
63
|
|
|
100
|
-
|
|
101
|
-
const binPath = getEnginePath();
|
|
102
|
-
const binDir = getEngineDir();
|
|
103
|
-
if (!binPath || !binDir) {
|
|
104
|
-
console.error("drift: Could not resolve engine directory (~/.drift/bin). Set HOME or USERPROFILE.");
|
|
105
|
-
return false;
|
|
106
|
-
}
|
|
107
|
-
if (!fs.existsSync(binPath)) {
|
|
108
|
-
const { plat, arch } = getPlatformKey();
|
|
109
|
-
const ext = process.platform === "win32" ? ".exe" : "";
|
|
110
|
-
const asset = `drift-engine-${plat}-${arch}${ext}`;
|
|
111
|
-
const url = `${ENGINE_BASE}/${asset}`;
|
|
112
|
-
process.stderr.write(`drift: Downloading engine (${asset})...\n`);
|
|
113
|
-
try {
|
|
114
|
-
await downloadFile(url, binPath);
|
|
115
|
-
} catch (e) {
|
|
116
|
-
console.error("drift: Download failed.", e.message);
|
|
117
|
-
console.error("drift: Run the engine manually or set DRIFT_ENGINE_BASE_URL.");
|
|
118
|
-
return false;
|
|
119
|
-
}
|
|
120
|
-
if (process.platform !== "win32") {
|
|
121
|
-
try { fs.chmodSync(binPath, 0o755); } catch (_) {}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
const child = spawn(binPath, [], {
|
|
125
|
-
detached: true,
|
|
126
|
-
stdio: "ignore",
|
|
127
|
-
cwd: binDir,
|
|
128
|
-
env: { ...process.env, DRIFT_ENGINE_PORT: ENGINE_PORT },
|
|
129
|
-
});
|
|
130
|
-
child.unref();
|
|
131
|
-
return waitForEngine();
|
|
132
|
-
}
|
|
64
|
+
pipx install drift-ml
|
|
133
65
|
|
|
134
|
-
|
|
135
|
-
const userBackend = process.env.DRIFT_BACKEND_URL;
|
|
136
|
-
if (userBackend) {
|
|
137
|
-
// User runs engine elsewhere; skip download/start and connect to their URL.
|
|
138
|
-
} else if (await engineRunning()) {
|
|
139
|
-
// Engine already running locally.
|
|
140
|
-
} else {
|
|
141
|
-
const engineStarted = await ensureEngine().catch(() => false);
|
|
142
|
-
if (!engineStarted) {
|
|
143
|
-
console.error("drift: Engine did not start. Run the engine manually or set DRIFT_BACKEND_URL to a running engine URL.");
|
|
144
|
-
process.exit(1);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
66
|
+
Then run:
|
|
147
67
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
console.error("drift: Python is required for the chat CLI. Install Python 3 and ensure `python` or `python3` is on your PATH.");
|
|
68
|
+
drift
|
|
69
|
+
`);
|
|
151
70
|
process.exit(1);
|
|
152
71
|
}
|
|
153
72
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
stdio: ["inherit", "pipe", "inherit"],
|
|
157
|
-
});
|
|
158
|
-
if (pip.status !== 0) {
|
|
159
|
-
console.error("drift: Failed to install or upgrade the drift Python package.");
|
|
160
|
-
process.exit(pip.status === null ? 1 : pip.status);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const backendUrl = userBackend || `http://127.0.0.1:${ENGINE_PORT}`;
|
|
164
|
-
const run = spawnSync(python, ["-m", "drift"], {
|
|
165
|
-
encoding: "utf8",
|
|
73
|
+
// Run the Python drift and forward stdin/stdout
|
|
74
|
+
const result = spawnSync(driftPath, process.argv.slice(2), {
|
|
166
75
|
stdio: "inherit",
|
|
167
|
-
env:
|
|
76
|
+
env: process.env,
|
|
168
77
|
});
|
|
169
|
-
|
|
78
|
+
|
|
79
|
+
process.exit(result.status === null ? (result.signal ? 128 + 9 : 1) : result.status);
|
|
170
80
|
}
|
|
171
81
|
|
|
172
|
-
main()
|
|
173
|
-
console.error("drift:", e.message);
|
|
174
|
-
process.exit(1);
|
|
175
|
-
});
|
|
82
|
+
main();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "drift-ml",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
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).",
|
|
5
5
|
"bin": {
|
|
6
6
|
"drift": "./bin/drift.js"
|