@infrarix/locopilot 1.1.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.
Files changed (100) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +239 -0
  3. package/dist/api/index.js +79 -0
  4. package/dist/api/index.js.map +1 -0
  5. package/dist/api/middleware/rateLimiter.js +27 -0
  6. package/dist/api/middleware/rateLimiter.js.map +1 -0
  7. package/dist/api/routes/chat.js +75 -0
  8. package/dist/api/routes/chat.js.map +1 -0
  9. package/dist/api/routes/completions.js +72 -0
  10. package/dist/api/routes/completions.js.map +1 -0
  11. package/dist/api/routes/health.js +52 -0
  12. package/dist/api/routes/health.js.map +1 -0
  13. package/dist/api/routes/models.js +50 -0
  14. package/dist/api/routes/models.js.map +1 -0
  15. package/dist/api/routes/training.js +10 -0
  16. package/dist/api/routes/training.js.map +1 -0
  17. package/dist/api/services/localRouter.js +201 -0
  18. package/dist/api/services/localRouter.js.map +1 -0
  19. package/dist/api/services/localStubs.js +28 -0
  20. package/dist/api/services/localStubs.js.map +1 -0
  21. package/dist/api/services/ollama.js +22 -0
  22. package/dist/api/services/ollama.js.map +1 -0
  23. package/dist/api/types.js +3 -0
  24. package/dist/api/types.js.map +1 -0
  25. package/dist/api/utils/sse.js +78 -0
  26. package/dist/api/utils/sse.js.map +1 -0
  27. package/dist/cli/commands/doctor.js +230 -0
  28. package/dist/cli/commands/doctor.js.map +1 -0
  29. package/dist/cli/commands/expose.js +98 -0
  30. package/dist/cli/commands/expose.js.map +1 -0
  31. package/dist/cli/commands/init.js +340 -0
  32. package/dist/cli/commands/init.js.map +1 -0
  33. package/dist/cli/commands/login.js +116 -0
  34. package/dist/cli/commands/login.js.map +1 -0
  35. package/dist/cli/commands/logout.js +38 -0
  36. package/dist/cli/commands/logout.js.map +1 -0
  37. package/dist/cli/commands/logs.js +95 -0
  38. package/dist/cli/commands/logs.js.map +1 -0
  39. package/dist/cli/commands/models.js +106 -0
  40. package/dist/cli/commands/models.js.map +1 -0
  41. package/dist/cli/commands/start.js +132 -0
  42. package/dist/cli/commands/start.js.map +1 -0
  43. package/dist/cli/commands/train.js +211 -0
  44. package/dist/cli/commands/train.js.map +1 -0
  45. package/dist/cli/commands/usage.js +43 -0
  46. package/dist/cli/commands/usage.js.map +1 -0
  47. package/dist/cli/commands/whoami.js +54 -0
  48. package/dist/cli/commands/whoami.js.map +1 -0
  49. package/dist/cli/index.js +49 -0
  50. package/dist/cli/index.js.map +1 -0
  51. package/dist/cli/utils/banner.js +177 -0
  52. package/dist/cli/utils/banner.js.map +1 -0
  53. package/dist/cli/utils/paths.js +37 -0
  54. package/dist/cli/utils/paths.js.map +1 -0
  55. package/dist/cloud/client.js +157 -0
  56. package/dist/cloud/client.js.map +1 -0
  57. package/dist/shared/constants.js +39 -0
  58. package/dist/shared/constants.js.map +1 -0
  59. package/dist/shared/crypto.js +26 -0
  60. package/dist/shared/crypto.js.map +1 -0
  61. package/dist/shared/db/pool.js +83 -0
  62. package/dist/shared/db/pool.js.map +1 -0
  63. package/dist/shared/errors.js +59 -0
  64. package/dist/shared/errors.js.map +1 -0
  65. package/dist/shared/index.js +24 -0
  66. package/dist/shared/index.js.map +1 -0
  67. package/dist/shared/ndjson.js +39 -0
  68. package/dist/shared/ndjson.js.map +1 -0
  69. package/dist/shared/runtime/ollama/index.js +55 -0
  70. package/dist/shared/runtime/ollama/index.js.map +1 -0
  71. package/dist/shared/types.js +3 -0
  72. package/dist/shared/types.js.map +1 -0
  73. package/dist/training/adapters/axolotl.js +83 -0
  74. package/dist/training/adapters/axolotl.js.map +1 -0
  75. package/dist/training/adapters/axolotl_runner.py +38 -0
  76. package/dist/training/adapters/mlx.js +57 -0
  77. package/dist/training/adapters/mlx.js.map +1 -0
  78. package/dist/training/adapters/mlx_runner.py +175 -0
  79. package/dist/training/adapters/unsloth.js +57 -0
  80. package/dist/training/adapters/unsloth.js.map +1 -0
  81. package/dist/training/adapters/unsloth_runner.py +116 -0
  82. package/dist/training/index.js +47 -0
  83. package/dist/training/index.js.map +1 -0
  84. package/dist/training/types.js +18 -0
  85. package/dist/training/types.js.map +1 -0
  86. package/dist/training/validator.js +67 -0
  87. package/dist/training/validator.js.map +1 -0
  88. package/dist/worker/executor.js +98 -0
  89. package/dist/worker/executor.js.map +1 -0
  90. package/dist/worker/handlers.js +197 -0
  91. package/dist/worker/handlers.js.map +1 -0
  92. package/dist/worker/index.js +45 -0
  93. package/dist/worker/index.js.map +1 -0
  94. package/dist/worker/logStore.js +24 -0
  95. package/dist/worker/logStore.js.map +1 -0
  96. package/dist/worker/types.js +3 -0
  97. package/dist/worker/types.js.map +1 -0
  98. package/dist/worker/worker.js +12 -0
  99. package/dist/worker/worker.js.map +1 -0
  100. package/package.json +81 -0
@@ -0,0 +1,98 @@
1
+ 'use strict';
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const commander_1 = require("commander");
7
+ const child_process_1 = require("child_process");
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const fs_1 = __importDefault(require("fs"));
10
+ const paths_1 = require("../utils/paths");
11
+ function saveTunnelUrl(url) {
12
+ try {
13
+ if (!fs_1.default.existsSync(paths_1.HOME_DIR))
14
+ fs_1.default.mkdirSync(paths_1.HOME_DIR, { recursive: true });
15
+ let config = {};
16
+ if (fs_1.default.existsSync(paths_1.CONFIG_PATH)) {
17
+ config = JSON.parse(fs_1.default.readFileSync(paths_1.CONFIG_PATH, 'utf8'));
18
+ }
19
+ config.tunnel = { url, updatedAt: new Date().toISOString() };
20
+ fs_1.default.writeFileSync(paths_1.CONFIG_PATH, JSON.stringify(config, null, 2) + '\n', { mode: 0o600 });
21
+ }
22
+ catch {
23
+ // non-fatal
24
+ }
25
+ }
26
+ function cloudflaredInstallHint() {
27
+ switch (process.platform) {
28
+ case 'darwin':
29
+ return 'brew install cloudflare/cloudflare/cloudflared';
30
+ case 'win32':
31
+ return 'winget install --id Cloudflare.cloudflared (or download from https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/)';
32
+ default:
33
+ return 'curl -L --output cloudflared.deb https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64.deb && sudo dpkg -i cloudflared.deb';
34
+ }
35
+ }
36
+ // cloudflare quick tunnels emit the URL in stderr; named tunnels may use stdout
37
+ const TUNNEL_URL_RE = /https:\/\/[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*\.trycloudflare\.com/;
38
+ const cmd = new commander_1.Command('expose').description('Expose the local API over a public Cloudflare Tunnel');
39
+ cmd.action(() => {
40
+ (0, paths_1.loadEnv)();
41
+ const port = process.env.API_PORT ?? '8080';
42
+ const localUrl = `http://localhost:${port}`;
43
+ console.log(chalk_1.default.bold(`\n Exposing ${localUrl} via Cloudflare Tunnel...\n`));
44
+ console.log(chalk_1.default.gray(' Requires cloudflared — https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/\n'));
45
+ // On Windows the binary is still invoked as 'cloudflared' (PATH resolves .exe automatically)
46
+ const binary = process.platform === 'win32' ? 'cloudflared.exe' : 'cloudflared';
47
+ const proc = (0, child_process_1.spawn)(binary, ['tunnel', '--no-autoupdate', '--url', localUrl], {
48
+ stdio: ['ignore', 'pipe', 'pipe'],
49
+ // shell: false — always use execFile semantics to avoid injection
50
+ shell: false,
51
+ });
52
+ let urlPrinted = false;
53
+ const onData = (data) => {
54
+ const text = data.toString();
55
+ // Print cloudflared output dimmed — useful for seeing connection progress
56
+ process.stderr.write(chalk_1.default.gray(text));
57
+ if (!urlPrinted) {
58
+ const match = TUNNEL_URL_RE.exec(text);
59
+ if (match) {
60
+ urlPrinted = true;
61
+ console.log(chalk_1.default.green.bold(`\n ✔ Public URL: ${match[0]}\n`));
62
+ saveTunnelUrl(match[0]);
63
+ }
64
+ }
65
+ };
66
+ proc.stdout?.on('data', onData);
67
+ proc.stderr?.on('data', onData);
68
+ proc.on('error', (err) => {
69
+ if (err.code === 'ENOENT') {
70
+ console.error(chalk_1.default.red('\n cloudflared not found.'));
71
+ console.error(chalk_1.default.gray(` Install: ${cloudflaredInstallHint()}\n`));
72
+ }
73
+ else {
74
+ console.error(chalk_1.default.red(`\n Tunnel error: ${err.message}\n`));
75
+ }
76
+ process.exit(1);
77
+ });
78
+ // Forward Ctrl+C to the tunnel process for clean shutdown
79
+ process.on('SIGINT', () => {
80
+ try {
81
+ proc.kill('SIGINT');
82
+ }
83
+ catch {
84
+ /* already exited */
85
+ }
86
+ });
87
+ process.on('SIGTERM', () => {
88
+ try {
89
+ proc.kill('SIGTERM');
90
+ }
91
+ catch {
92
+ /* already exited */
93
+ }
94
+ });
95
+ proc.on('exit', (code) => process.exit(code ?? 0));
96
+ });
97
+ exports.default = cmd;
98
+ //# sourceMappingURL=expose.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"expose.js","sourceRoot":"","sources":["../../../src/cli/commands/expose.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,340 @@
1
+ 'use strict';
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ const commander_1 = require("commander");
40
+ const chalk_1 = __importDefault(require("chalk"));
41
+ const ora_1 = __importDefault(require("ora"));
42
+ const fs_1 = __importDefault(require("fs"));
43
+ const child_process_1 = require("child_process");
44
+ const paths = __importStar(require("../utils/paths"));
45
+ const banner_1 = require("../utils/banner");
46
+ const shared_1 = require("../../shared");
47
+ const cmd = new commander_1.Command('init').description('Initialize LocoPilot — installs Ollama, sets up local database, writes config');
48
+ cmd.action(async () => {
49
+ (0, banner_1.printBanner)();
50
+ console.log(chalk_1.default.bold(' LocoPilot Setup\n'));
51
+ paths.ensureHomeDir();
52
+ const platform = process.platform;
53
+ const arch = process.arch;
54
+ // ── 1. Ollama ────────────────────────────────────────────────────────────
55
+ console.log(chalk_1.default.cyan(' [1/4] Checking Ollama...'));
56
+ await ensureOllamaInstalled(platform);
57
+ await ensureOllamaRunning(platform);
58
+ // ── 2. Python 3 ──────────────────────────────────────────────────────────
59
+ console.log(chalk_1.default.cyan('\n [2/4] Checking Python 3 (required for training adapters)...'));
60
+ checkPython(platform);
61
+ // ── 3. Database ──────────────────────────────────────────────────────────
62
+ console.log(chalk_1.default.cyan('\n [3/4] Initializing local database...'));
63
+ process.env.SQLITE_PATH = paths.SQLITE_PATH;
64
+ const dbSpinner = (0, ora_1.default)(' Creating tables...').start();
65
+ try {
66
+ await initializeSQLite();
67
+ dbSpinner.succeed(chalk_1.default.green(` SQLite ready at ${paths.SQLITE_PATH}`));
68
+ }
69
+ catch (err) {
70
+ dbSpinner.fail(chalk_1.default.red(` Database error: ${err.message}`));
71
+ process.exit(1);
72
+ }
73
+ // ── 4. Config file ───────────────────────────────────────────────────────
74
+ console.log(chalk_1.default.cyan('\n [4/4] Writing default config...'));
75
+ if (!fs_1.default.existsSync(paths.ENV_PATH)) {
76
+ fs_1.default.writeFileSync(paths.ENV_PATH, [
77
+ '# LocoPilot local config — edit as needed',
78
+ `SQLITE_PATH=${paths.SQLITE_PATH}`,
79
+ 'OLLAMA_HOST=http://localhost:11434',
80
+ 'API_PORT=8080',
81
+ '',
82
+ '# Uncomment to override the LocoPilot Cloud URL (for local dev):',
83
+ '# LOCOPILOT_CLOUD_URL=http://localhost:8081',
84
+ ].join('\n') + '\n', { encoding: 'utf8' });
85
+ console.log(chalk_1.default.green(` ✔ Config written to ${paths.ENV_PATH}`));
86
+ }
87
+ else {
88
+ console.log(chalk_1.default.gray(` Config already exists at ${paths.ENV_PATH}`));
89
+ }
90
+ // ── Summary ──────────────────────────────────────────────────────────────
91
+ console.log(chalk_1.default.bold('\n Setup complete!\n'));
92
+ if (platform === 'darwin' && arch === 'arm64') {
93
+ console.log(chalk_1.default.gray(' Apple Silicon detected — training will use the MLX adapter (mlx-lm).'));
94
+ console.log(chalk_1.default.gray(' Install: ') + chalk_1.default.white('pip3 install mlx-lm\n'));
95
+ }
96
+ else {
97
+ console.log(chalk_1.default.gray(' Training uses Unsloth or Axolotl (Linux/Windows).'));
98
+ console.log(chalk_1.default.gray(' Install: ') + chalk_1.default.white('pip3 install unsloth trl transformers datasets\n'));
99
+ }
100
+ console.log(chalk_1.default.gray(' Run ') + chalk_1.default.white('locopilot start') + chalk_1.default.gray(' to launch the local API.'));
101
+ console.log(chalk_1.default.gray(' Run ') + chalk_1.default.white('locopilot models pull llama3') + chalk_1.default.gray(' to download a model.'));
102
+ console.log(chalk_1.default.gray(' Run ') +
103
+ chalk_1.default.white('locopilot login') +
104
+ chalk_1.default.gray(' to enable Pro tier (cloud GPU, remote models).\n'));
105
+ });
106
+ // ── Ollama install ────────────────────────────────────────────────────────────
107
+ async function ensureOllamaInstalled(platform) {
108
+ // Check if ollama binary is already available
109
+ if (isCommandAvailable('ollama')) {
110
+ let version = '';
111
+ try {
112
+ version = (0, child_process_1.execFileSync)('ollama', ['--version'], { encoding: 'utf8' }).trim();
113
+ }
114
+ catch {
115
+ /* ignore */
116
+ }
117
+ console.log(chalk_1.default.green(` ✔ Ollama installed ${version ? chalk_1.default.gray(`(${version})`) : ''}`));
118
+ return;
119
+ }
120
+ console.log(chalk_1.default.yellow(' Ollama not found — attempting installation...'));
121
+ const spinner = (0, ora_1.default)(' Installing Ollama...').start();
122
+ try {
123
+ if (platform === 'darwin') {
124
+ // Prefer brew cask; fall back to formula (headless)
125
+ if (isCommandAvailable('brew')) {
126
+ (0, child_process_1.execSync)('brew install --cask ollama', { stdio: 'ignore' });
127
+ }
128
+ else {
129
+ spinner.fail(chalk_1.default.red(' Homebrew not found. Install Homebrew first: https://brew.sh'));
130
+ console.log(chalk_1.default.gray(' Then run: brew install --cask ollama'));
131
+ console.log(chalk_1.default.gray(' Or download from: https://ollama.ai/download'));
132
+ process.exit(1);
133
+ }
134
+ }
135
+ else if (platform === 'linux') {
136
+ (0, child_process_1.execSync)('curl -fsSL https://ollama.com/install.sh | sh', { stdio: 'ignore', shell: '/bin/sh' });
137
+ }
138
+ else if (platform === 'win32') {
139
+ if (isCommandAvailable('winget')) {
140
+ (0, child_process_1.execSync)('winget install -e --id Ollama.Ollama', { stdio: 'ignore', shell: 'cmd.exe' });
141
+ }
142
+ else {
143
+ spinner.fail(chalk_1.default.red(' winget not found.'));
144
+ console.log(chalk_1.default.gray(' Download Ollama from: https://ollama.ai/download'));
145
+ process.exit(1);
146
+ }
147
+ }
148
+ else {
149
+ spinner.fail(chalk_1.default.yellow(` Unsupported platform: ${platform}`));
150
+ console.log(chalk_1.default.gray(' Install manually: https://ollama.ai/download'));
151
+ return;
152
+ }
153
+ spinner.succeed(chalk_1.default.green(' Ollama installed successfully'));
154
+ }
155
+ catch (err) {
156
+ spinner.fail(chalk_1.default.yellow(` Auto-install failed: ${err.message}`));
157
+ console.log(chalk_1.default.gray(' Install manually: https://ollama.ai/download'));
158
+ }
159
+ }
160
+ // ── Ollama service start ──────────────────────────────────────────────────────
161
+ async function ensureOllamaRunning(platform) {
162
+ const host = process.env.OLLAMA_HOST ?? 'http://localhost:11434';
163
+ // First check: is it already running?
164
+ try {
165
+ const res = await fetch(host, { signal: AbortSignal.timeout(3_000) });
166
+ if (res.ok) {
167
+ console.log(chalk_1.default.green(' ✔ Ollama service running'));
168
+ return;
169
+ }
170
+ }
171
+ catch {
172
+ /* not running */
173
+ }
174
+ // If the binary isn't on PATH, there's nothing to start — installation
175
+ // earlier must have failed. Print clear instructions and return rather
176
+ // than crashing on spawn ENOENT.
177
+ if (!isCommandAvailable('ollama')) {
178
+ console.log(chalk_1.default.yellow(' ⚠ Ollama binary not available — skipping service start.'));
179
+ printOllamaInstallHint(platform);
180
+ return;
181
+ }
182
+ console.log(chalk_1.default.yellow(' Ollama service not running — attempting to start...'));
183
+ if (platform === 'darwin') {
184
+ try {
185
+ (0, child_process_1.execSync)('brew services start ollama', { stdio: 'ignore' });
186
+ }
187
+ catch {
188
+ startOllamaBackground();
189
+ }
190
+ }
191
+ else if (platform === 'linux') {
192
+ try {
193
+ (0, child_process_1.execSync)('systemctl --user start ollama 2>/dev/null || ollama serve &', {
194
+ stdio: 'ignore',
195
+ shell: '/bin/sh',
196
+ });
197
+ }
198
+ catch {
199
+ startOllamaBackground();
200
+ }
201
+ }
202
+ else if (platform === 'win32') {
203
+ // On Windows, Ollama runs as a tray application — launch it.
204
+ startOllamaBackground();
205
+ }
206
+ else {
207
+ startOllamaBackground();
208
+ }
209
+ // Wait up to 10 s for Ollama to come up
210
+ const spinner = (0, ora_1.default)(' Waiting for Ollama to start...').start();
211
+ for (let i = 0; i < 20; i++) {
212
+ await new Promise((r) => setTimeout(r, 500));
213
+ try {
214
+ const res = await fetch(host, { signal: AbortSignal.timeout(1_000) });
215
+ if (res.ok) {
216
+ spinner.succeed(chalk_1.default.green(' Ollama service ready'));
217
+ return;
218
+ }
219
+ }
220
+ catch {
221
+ /* keep waiting */
222
+ }
223
+ }
224
+ spinner.warn(chalk_1.default.yellow(' Ollama did not respond within 10 s.'));
225
+ console.log(chalk_1.default.gray(' Make sure Ollama is running before using LocoPilot.'));
226
+ console.log(chalk_1.default.gray(' On macOS/Linux: ') + chalk_1.default.white('ollama serve'));
227
+ console.log(chalk_1.default.gray(' On Windows: open Ollama from Start menu\n'));
228
+ }
229
+ function startOllamaBackground() {
230
+ try {
231
+ const proc = (0, child_process_1.spawn)('ollama', ['serve'], {
232
+ detached: true,
233
+ stdio: 'ignore',
234
+ shell: false,
235
+ });
236
+ // spawn() does not throw synchronously on ENOENT — it emits an 'error'
237
+ // event. Without a listener, Node treats it as unhandled and crashes.
238
+ proc.on('error', () => {
239
+ /* binary missing or failed; surface elsewhere */
240
+ });
241
+ proc.unref();
242
+ }
243
+ catch {
244
+ /* synchronous failures (rare) */
245
+ }
246
+ }
247
+ function printOllamaInstallHint(platform) {
248
+ console.log(chalk_1.default.gray(' Install Ollama and re-run `locopilot init`:'));
249
+ if (platform === 'darwin') {
250
+ console.log(chalk_1.default.gray(' macOS: ') + chalk_1.default.white('brew install --cask ollama'));
251
+ console.log(chalk_1.default.gray(' ') + chalk_1.default.gray('or download from https://ollama.ai/download'));
252
+ }
253
+ else if (platform === 'linux') {
254
+ console.log(chalk_1.default.gray(' Linux: ') + chalk_1.default.white('curl -fsSL https://ollama.com/install.sh | sh'));
255
+ }
256
+ else if (platform === 'win32') {
257
+ console.log(chalk_1.default.gray(' Windows: ') + chalk_1.default.white('winget install Ollama.Ollama'));
258
+ console.log(chalk_1.default.gray(' ') + chalk_1.default.gray('or download from https://ollama.ai/download'));
259
+ }
260
+ else {
261
+ console.log(chalk_1.default.gray(' Manual: https://ollama.ai/download'));
262
+ }
263
+ }
264
+ // ── Python check ─────────────────────────────────────────────────────────────
265
+ function checkPython(platform) {
266
+ // On Windows: try 'python', 'python3' (py launcher). On Unix: 'python3'.
267
+ const candidates = platform === 'win32' ? ['python3', 'python', 'py'] : ['python3'];
268
+ for (const cmd of candidates) {
269
+ try {
270
+ const out = (0, child_process_1.execFileSync)(cmd, ['--version'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'] });
271
+ const version = (out || '').trim();
272
+ if (/Python 3\.\d+/.test(version)) {
273
+ console.log(chalk_1.default.green(` ✔ ${version} (${cmd})`));
274
+ return;
275
+ }
276
+ }
277
+ catch {
278
+ /* try next */
279
+ }
280
+ }
281
+ console.log(chalk_1.default.yellow(' ⚠ Python 3 not found.'));
282
+ console.log(chalk_1.default.gray(' Training adapters require Python 3.9+.'));
283
+ if (platform === 'darwin') {
284
+ console.log(chalk_1.default.gray(' Install: ') + chalk_1.default.white('brew install python3'));
285
+ }
286
+ else if (platform === 'win32') {
287
+ console.log(chalk_1.default.gray(' Install from: ') + chalk_1.default.white('https://www.python.org/downloads/'));
288
+ }
289
+ else {
290
+ console.log(chalk_1.default.gray(' Install: ') + chalk_1.default.white('sudo apt install python3 # or your distro equivalent'));
291
+ }
292
+ }
293
+ // ── SQLite schema ─────────────────────────────────────────────────────────────
294
+ async function initializeSQLite() {
295
+ // UUIDv4-compatible blob default for SQLite
296
+ const uuidDefault = `(lower(hex(randomblob(4))) || '-' || lower(hex(randomblob(2))) || '-4' || substr(lower(hex(randomblob(2))),2) || '-' || substr('89ab',abs(random()) % 4 + 1, 1) || substr(lower(hex(randomblob(2))),2) || '-' || lower(hex(randomblob(6))))`;
297
+ await (0, shared_1.query)(`
298
+ CREATE TABLE IF NOT EXISTS inference_logs (
299
+ id TEXT PRIMARY KEY DEFAULT ${uuidDefault},
300
+ api_key_id TEXT,
301
+ model TEXT NOT NULL,
302
+ provider TEXT NOT NULL,
303
+ tokens_in INTEGER,
304
+ tokens_out INTEGER,
305
+ latency_ms INTEGER,
306
+ ttfb_ms INTEGER,
307
+ status INTEGER,
308
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
309
+ )
310
+ `);
311
+ await (0, shared_1.query)(`
312
+ CREATE TABLE IF NOT EXISTS training_jobs (
313
+ id TEXT PRIMARY KEY,
314
+ framework TEXT NOT NULL,
315
+ status TEXT NOT NULL DEFAULT 'pending',
316
+ base_model TEXT NOT NULL,
317
+ dataset_path TEXT NOT NULL,
318
+ output_path TEXT,
319
+ config_json TEXT NOT NULL DEFAULT '{}',
320
+ error TEXT,
321
+ started_at TEXT,
322
+ completed_at TEXT,
323
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
324
+ )
325
+ `);
326
+ await (0, shared_1.query)(`CREATE INDEX IF NOT EXISTS idx_training_jobs_status ON training_jobs(status)`);
327
+ }
328
+ // ── Helpers ───────────────────────────────────────────────────────────────────
329
+ function isCommandAvailable(cmd) {
330
+ const which = process.platform === 'win32' ? 'where' : 'which';
331
+ try {
332
+ (0, child_process_1.execFileSync)(which, [cmd], { stdio: 'ignore' });
333
+ return true;
334
+ }
335
+ catch {
336
+ return false;
337
+ }
338
+ }
339
+ exports.default = cmd;
340
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,116 @@
1
+ 'use strict';
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const commander_1 = require("commander");
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const enquirer_1 = require("enquirer");
10
+ const paths_1 = require("../utils/paths");
11
+ const client_1 = require("../../cloud/client");
12
+ async function promptToken() {
13
+ const res = await (0, enquirer_1.prompt)({
14
+ type: 'password',
15
+ name: 'token',
16
+ message: 'Enter your LocoPilot API key (qs_...)',
17
+ });
18
+ return res.token.trim();
19
+ }
20
+ const cmd = new commander_1.Command('login').description('Authenticate with LocoPilot Cloud (enables Pro tier)');
21
+ cmd.option('--key <token>', 'API key starting with qs_');
22
+ cmd.action(async (opts) => {
23
+ let token = opts.key;
24
+ if (!token) {
25
+ console.log(chalk_1.default.bold('\n LocoPilot Login\n'));
26
+ console.log(chalk_1.default.gray(' Get your API key at https://locopilot.com/dashboard\n'));
27
+ try {
28
+ token = await promptToken();
29
+ }
30
+ catch {
31
+ // User cancelled prompt (Ctrl+C)
32
+ console.log();
33
+ process.exit(0);
34
+ }
35
+ }
36
+ if (!token) {
37
+ console.error(chalk_1.default.red(' No token provided.'));
38
+ process.exit(1);
39
+ }
40
+ if (!token.startsWith('qs_')) {
41
+ console.error(chalk_1.default.red(' Invalid token format — must start with qs_'));
42
+ console.error(chalk_1.default.gray(' Tokens look like: qs_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'));
43
+ process.exit(1);
44
+ }
45
+ if (token.length < 20) {
46
+ console.error(chalk_1.default.red(' Token too short — check for copy/paste errors.'));
47
+ process.exit(1);
48
+ }
49
+ // Validate token against cloud backend
50
+ console.log(chalk_1.default.gray('\n Verifying token...'));
51
+ try {
52
+ const res = await (0, client_1.callCloudAuthVerify)(`Bearer ${token}`);
53
+ if (res.status === 401) {
54
+ console.error(chalk_1.default.red(' Invalid API key — authentication failed.'));
55
+ console.error(chalk_1.default.gray(' Check your key at https://locopilot.com/dashboard'));
56
+ process.exit(1);
57
+ }
58
+ if (!res.ok) {
59
+ console.warn(chalk_1.default.yellow(` Warning: cloud verification returned ${res.status} — saving token anyway.`));
60
+ }
61
+ }
62
+ catch (err) {
63
+ const msg = err.message;
64
+ if (msg.includes('fetch failed') || msg.includes('ENOTFOUND') || msg.includes('timeout')) {
65
+ console.warn(chalk_1.default.yellow(' Warning: could not reach LocoPilot Cloud — saving token offline.'));
66
+ console.warn(chalk_1.default.gray(' Token will be verified on first use.'));
67
+ }
68
+ else {
69
+ console.warn(chalk_1.default.yellow(` Warning: verification skipped (${msg}) — saving token.`));
70
+ }
71
+ }
72
+ (0, paths_1.ensureHomeDir)();
73
+ // Preserve any existing non-token fields (e.g. tunnel URL)
74
+ let existing = {};
75
+ if (fs_1.default.existsSync(paths_1.CONFIG_PATH)) {
76
+ try {
77
+ existing = JSON.parse(fs_1.default.readFileSync(paths_1.CONFIG_PATH, 'utf8'));
78
+ }
79
+ catch {
80
+ /* start fresh */
81
+ }
82
+ }
83
+ fs_1.default.writeFileSync(paths_1.CONFIG_PATH, JSON.stringify({ ...existing, token }, null, 2) + '\n', { mode: 0o600 });
84
+ // Probe /api/auth/me so the user gets a clear "Pro" vs "Free vs past-due"
85
+ // line. Subscription state is NEVER cached locally — the CLI re-fetches
86
+ // on every cloud call. This printout is purely informational.
87
+ let planLine = chalk_1.default.green(' ✔ Logged in successfully.');
88
+ try {
89
+ const meRes = await (0, client_1.callCloudAuthMe)(`Bearer ${token}`);
90
+ if (meRes.ok) {
91
+ const me = (await meRes.json());
92
+ const plan = me.plan ?? 'free';
93
+ if (plan === 'pro_active') {
94
+ const renewsOn = me.current_period_end ? new Date(me.current_period_end).toLocaleDateString() : 'unknown';
95
+ planLine = chalk_1.default.green(` ✔ Logged in (Pro — active until ${renewsOn})`);
96
+ }
97
+ else if (plan === 'pro_past_due') {
98
+ planLine = chalk_1.default.yellow(' ✔ Logged in (Pro — past due, update billing at https://locopilot.com/dashboard)');
99
+ }
100
+ else if (plan === 'pro_canceled' || plan === 'pro_inactive') {
101
+ planLine = chalk_1.default.yellow(` ✔ Logged in (subscription ${plan.replace('pro_', '')} — re-subscribe at https://locopilot.com/pricing)`);
102
+ }
103
+ else {
104
+ planLine = chalk_1.default.green(' ✔ Logged in (Free — upgrade at https://locopilot.com/pricing for cloud features)');
105
+ }
106
+ }
107
+ }
108
+ catch {
109
+ // /api/auth/me unreachable; fall through to generic success
110
+ }
111
+ console.log('\n' + planLine + '\n');
112
+ console.log(chalk_1.default.gray(' Token stored at: ') + chalk_1.default.white(paths_1.CONFIG_PATH));
113
+ console.log(chalk_1.default.gray(' Run `locopilot logout` to remove it.\n'));
114
+ });
115
+ exports.default = cmd;
116
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../../src/cli/commands/login.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ 'use strict';
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const commander_1 = require("commander");
7
+ const chalk_1 = __importDefault(require("chalk"));
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const paths_1 = require("../utils/paths");
10
+ const cmd = new commander_1.Command('logout').description('Remove stored credentials and disable Pro tier');
11
+ cmd.action(() => {
12
+ if (!fs_1.default.existsSync(paths_1.CONFIG_PATH)) {
13
+ console.log(chalk_1.default.gray('\n Not logged in — nothing to remove.\n'));
14
+ return;
15
+ }
16
+ let config = {};
17
+ try {
18
+ config = JSON.parse(fs_1.default.readFileSync(paths_1.CONFIG_PATH, 'utf8'));
19
+ }
20
+ catch {
21
+ // Corrupted config — remove entirely
22
+ }
23
+ if (!config.token) {
24
+ console.log(chalk_1.default.gray('\n Not logged in — nothing to remove.\n'));
25
+ return;
26
+ }
27
+ delete config.token;
28
+ if (Object.keys(config).length === 0) {
29
+ fs_1.default.unlinkSync(paths_1.CONFIG_PATH);
30
+ }
31
+ else {
32
+ fs_1.default.writeFileSync(paths_1.CONFIG_PATH, JSON.stringify(config, null, 2) + '\n', { mode: 0o600 });
33
+ }
34
+ console.log(chalk_1.default.green('\n ✔ Logged out. Pro tier disabled.\n'));
35
+ console.log(chalk_1.default.gray(' Run `locopilot login` to re-enable Pro tier.\n'));
36
+ });
37
+ exports.default = cmd;
38
+ //# sourceMappingURL=logout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logout.js","sourceRoot":"","sources":["../../../src/cli/commands/logout.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;;;;;AAEb,yCAAoC;AACpC,kDAA0B;AAC1B,4CAAoB;AACpB,0CAA6C;AAE7C,MAAM,GAAG,GAAG,IAAI,mBAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,CAAC,gDAAgD,CAAC,CAAC;AAEhG,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE;IACd,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,mBAAW,CAAC,EAAE,CAAC;QAChC,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC,CAAC;QACpE,OAAO;IACT,CAAC;IAED,IAAI,MAAM,GAA4B,EAAE,CAAC;IACzC,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAE,CAAC,YAAY,CAAC,mBAAW,EAAE,MAAM,CAAC,CAA4B,CAAC;IACvF,CAAC;IAAC,MAAM,CAAC;QACP,qCAAqC;IACvC,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAClB,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,0CAA0C,CAAC,CAAC,CAAC;QACpE,OAAO;IACT,CAAC;IAED,OAAO,MAAM,CAAC,KAAK,CAAC;IAEpB,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrC,YAAE,CAAC,UAAU,CAAC,mBAAW,CAAC,CAAC;IAC7B,CAAC;SAAM,CAAC;QACN,YAAE,CAAC,aAAa,CAAC,mBAAW,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACzF,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC,CAAC;IACnE,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,kDAAkD,CAAC,CAAC,CAAC;AAC9E,CAAC,CAAC,CAAC;AAEH,kBAAe,GAAG,CAAC"}