@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 @@
1
+ {"version":3,"file":"training.js","sourceRoot":"","sources":["../../../src/api/routes/training.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAUb,iCAIC;AAXD,yCAAgD;AAOjC,KAAK,UAAU,cAAc,CAAC,OAAwB;IACnE,OAAO,CAAC,IAAI,CAA0B,gBAAgB,EAAE,yBAAgB,CAAC,MAAM,CAAC,CAAC;IACjF,OAAO,CAAC,GAAG,CAA0B,oBAAoB,EAAE,yBAAgB,CAAC,SAAS,CAAC,CAAC;IACvF,OAAO,CAAC,GAAG,CAA0B,yBAAyB,EAAE,yBAAgB,CAAC,UAAU,CAAC,CAAC;AAC/F,CAAC"}
@@ -0,0 +1,201 @@
1
+ 'use strict';
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createLocalRouter = createLocalRouter;
4
+ const shared_1 = require("../../shared");
5
+ const client_1 = require("../../cloud/client");
6
+ async function createLocalRouter() {
7
+ return {
8
+ async resolve(requestedModel, isProUser) {
9
+ if (!requestedModel) {
10
+ return isProUser ? shared_1.PROVIDERS.REMOTE : shared_1.PROVIDERS.NOT_FOUND;
11
+ }
12
+ try {
13
+ const models = await (0, shared_1.getLocalModels)();
14
+ if (models.find((m) => m.name === requestedModel))
15
+ return shared_1.PROVIDERS.LOCAL;
16
+ const prefix = requestedModel.split(':')[0];
17
+ if (models.find((m) => m.name.startsWith(prefix)))
18
+ return shared_1.PROVIDERS.LOCAL;
19
+ }
20
+ catch (err) {
21
+ // Ollama unavailable — log and fall through to remote/not_found
22
+ console.warn('[router] Ollama unreachable:', err.message);
23
+ }
24
+ return isProUser ? shared_1.PROVIDERS.REMOTE : shared_1.PROVIDERS.NOT_FOUND;
25
+ },
26
+ async stream(provider, body, rawRes, sse, signal, authHeader) {
27
+ const startTime = Date.now();
28
+ const chatId = sse.generateChatId();
29
+ const isStreaming = body.stream !== false;
30
+ const tokensIn = sse.estimateTokens(body.messages);
31
+ const usage = {
32
+ model: body.model,
33
+ provider,
34
+ tokensIn,
35
+ tokensOut: 0,
36
+ latencyMs: 0,
37
+ ttfbMs: 0,
38
+ status: 200,
39
+ };
40
+ try {
41
+ if (provider === shared_1.PROVIDERS.LOCAL) {
42
+ const content = await streamFromOllama(body, rawRes, usage, chatId, isStreaming, startTime, sse, signal);
43
+ if (!isStreaming) {
44
+ const response = sse.buildCompletion(body.model, content, usage);
45
+ rawRes.setHeader('Content-Type', 'application/json');
46
+ rawRes.end(JSON.stringify(response));
47
+ }
48
+ }
49
+ else {
50
+ await streamFromCloudProxy(body, rawRes, usage, isStreaming, signal, authHeader ?? '');
51
+ }
52
+ usage.latencyMs = Date.now() - startTime;
53
+ return { usage };
54
+ }
55
+ catch (err) {
56
+ // Pro-subscription failures are NOT a connection problem — they're a
57
+ // billing problem. Surface them to the caller with a clean 403 +
58
+ // upgrade URL instead of falling back to local or returning 503.
59
+ if (err instanceof client_1.ProSubscriptionRequiredError) {
60
+ usage.status = 403;
61
+ usage.latencyMs = Date.now() - startTime;
62
+ if (!rawRes.headersSent) {
63
+ rawRes.setHeader('Content-Type', 'application/json');
64
+ rawRes.writeHead(403);
65
+ rawRes.end(JSON.stringify({
66
+ error: 'pro_subscription_required',
67
+ message: err.message,
68
+ upgrade_url: err.upgradeUrl,
69
+ }));
70
+ }
71
+ else if (isStreaming) {
72
+ sse.writeSSEError(rawRes, `Pro subscription not active. Manage at: ${err.upgradeUrl}`);
73
+ }
74
+ throw err;
75
+ }
76
+ console.error('[local-router] streaming failed:', err);
77
+ usage.status = 503;
78
+ usage.latencyMs = Date.now() - startTime;
79
+ if (isStreaming) {
80
+ sse.writeSSEError(rawRes, 'Provider unavailable');
81
+ }
82
+ else {
83
+ rawRes.setHeader('Content-Type', 'application/json');
84
+ rawRes.writeHead(503);
85
+ rawRes.end(JSON.stringify({ error: 'Provider unavailable' }));
86
+ }
87
+ throw new shared_1.ProviderError();
88
+ }
89
+ },
90
+ };
91
+ }
92
+ async function streamFromOllama(body, rawRes, usage, chatId, isStreaming, startTime, sse, signal) {
93
+ const ollamaRes = await (0, shared_1.streamChat)(body, signal);
94
+ if (!ollamaRes.body)
95
+ throw new Error('Ollama returned no body');
96
+ const reader = ollamaRes.body.getReader();
97
+ const decoder = new TextDecoder();
98
+ const parser = (0, shared_1.createNdjsonParser)();
99
+ let firstChunk = true;
100
+ let collectedContent = '';
101
+ try {
102
+ while (true) {
103
+ const { done, value } = await reader.read();
104
+ if (done)
105
+ break;
106
+ const chunk = decoder.decode(value, { stream: true });
107
+ const objects = parser.feed(chunk);
108
+ for (const obj of objects) {
109
+ const o = obj;
110
+ if (firstChunk) {
111
+ usage.ttfbMs = Date.now() - startTime;
112
+ firstChunk = false;
113
+ }
114
+ const content = o?.message?.content;
115
+ if (content) {
116
+ usage.tokensOut++;
117
+ collectedContent += content;
118
+ if (isStreaming)
119
+ sse.writeSSE(rawRes, sse.buildChunk(body.model, content, chatId));
120
+ }
121
+ if (o?.done === true) {
122
+ if (typeof o.prompt_eval_count === 'number')
123
+ usage.tokensIn = o.prompt_eval_count;
124
+ if (typeof o.eval_count === 'number')
125
+ usage.tokensOut = o.eval_count;
126
+ }
127
+ }
128
+ }
129
+ const remaining = parser.flush();
130
+ for (const obj of remaining) {
131
+ const o = obj;
132
+ const content = o?.message?.content;
133
+ if (content) {
134
+ usage.tokensOut++;
135
+ collectedContent += content;
136
+ if (isStreaming)
137
+ sse.writeSSE(rawRes, sse.buildChunk(body.model, content, chatId));
138
+ }
139
+ if (o?.done === true) {
140
+ if (typeof o.prompt_eval_count === 'number')
141
+ usage.tokensIn = o.prompt_eval_count;
142
+ if (typeof o.eval_count === 'number')
143
+ usage.tokensOut = o.eval_count;
144
+ }
145
+ }
146
+ if (isStreaming) {
147
+ sse.writeSSE(rawRes, sse.buildChunk(body.model, null, chatId, 'stop'));
148
+ sse.endSSE(rawRes);
149
+ }
150
+ return collectedContent;
151
+ }
152
+ finally {
153
+ reader.releaseLock();
154
+ }
155
+ }
156
+ async function streamFromCloudProxy(body, rawRes, usage, isStreaming, signal, authHeader) {
157
+ if (!authHeader)
158
+ throw new shared_1.ProviderError();
159
+ const startTime = Date.now();
160
+ const cloudRes = await (0, client_1.callCloudInference)(body, authHeader, signal);
161
+ if (!cloudRes.ok) {
162
+ throw new shared_1.ProviderError();
163
+ }
164
+ if (!cloudRes.body) {
165
+ throw new shared_1.ProviderError();
166
+ }
167
+ if (!rawRes.headersSent) {
168
+ if (isStreaming) {
169
+ rawRes.setHeader('Content-Type', 'text/event-stream');
170
+ rawRes.setHeader('Cache-Control', 'no-cache');
171
+ rawRes.setHeader('Connection', 'keep-alive');
172
+ }
173
+ else {
174
+ rawRes.setHeader('Content-Type', 'application/json');
175
+ }
176
+ rawRes.writeHead(200);
177
+ }
178
+ const reader = cloudRes.body.getReader();
179
+ let firstChunk = true;
180
+ let collectedContent = '';
181
+ const decoder = new TextDecoder();
182
+ try {
183
+ while (true) {
184
+ const { done, value } = await reader.read();
185
+ if (done)
186
+ break;
187
+ if (firstChunk) {
188
+ usage.ttfbMs = Date.now() - startTime;
189
+ firstChunk = false;
190
+ }
191
+ rawRes.write(value);
192
+ collectedContent += decoder.decode(value, { stream: true });
193
+ }
194
+ }
195
+ finally {
196
+ reader.releaseLock();
197
+ rawRes.end();
198
+ }
199
+ return collectedContent;
200
+ }
201
+ //# sourceMappingURL=localRouter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"localRouter.js","sourceRoot":"","sources":["../../../src/api/services/localRouter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createAuthMiddleware = createAuthMiddleware;
4
+ exports.createUsageTracker = createUsageTracker;
5
+ async function createAuthMiddleware() {
6
+ return {
7
+ async validate(authHeader) {
8
+ // No header → Free tier (anonymous local user)
9
+ if (!authHeader)
10
+ return null;
11
+ const raw = authHeader.replace(/^Bearer\s+/i, '');
12
+ // Only qs_ tokens are Pro tokens. Anything else is treated as anonymous.
13
+ // Actual token validation happens cloud-side when the request is proxied.
14
+ if (!raw.startsWith('qs_'))
15
+ return null;
16
+ // Return a stub key with a very high local rate limit — cloud enforces the real limit.
17
+ return { id: 'pro-user', name: 'pro', rate_limit_rpm: 9999, rate_window_seconds: 60 };
18
+ },
19
+ };
20
+ }
21
+ async function createUsageTracker() {
22
+ return {
23
+ async record(_usage) {
24
+ // Usage tracking is cloud-side only (Pro tier); no-op locally.
25
+ },
26
+ };
27
+ }
28
+ //# sourceMappingURL=localStubs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"localStubs.js","sourceRoot":"","sources":["../../../src/api/services/localStubs.ts"],"names":[],"mappings":";;AAEA,oDAaC;AAED,gDAMC;AArBM,KAAK,UAAU,oBAAoB;IACxC,OAAO;QACL,KAAK,CAAC,QAAQ,CAAC,UAAmB;YAChC,+CAA+C;YAC/C,IAAI,CAAC,UAAU;gBAAE,OAAO,IAAI,CAAC;YAC7B,MAAM,GAAG,GAAG,UAAU,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;YAClD,yEAAyE;YACzE,0EAA0E;YAC1E,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC;gBAAE,OAAO,IAAI,CAAC;YACxC,uFAAuF;YACvF,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,mBAAmB,EAAE,EAAE,EAAE,CAAC;QACxF,CAAC;KACF,CAAC;AACJ,CAAC;AAEM,KAAK,UAAU,kBAAkB;IACtC,OAAO;QACL,KAAK,CAAC,MAAM,CAAC,MAAiB;YAC5B,+DAA+D;QACjE,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,22 @@
1
+ 'use strict';
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getLocalModels = getLocalModels;
4
+ exports.checkOllama = checkOllama;
5
+ const shared_1 = require("../../shared");
6
+ async function getLocalModels() {
7
+ const res = await fetch(`${shared_1.OLLAMA_HOST}/api/tags`, {
8
+ signal: AbortSignal.timeout(shared_1.OLLAMA_LIST_TIMEOUT_MS),
9
+ });
10
+ if (!res.ok)
11
+ throw new Error(`Ollama unreachable: ${res.status}`);
12
+ const data = (await res.json());
13
+ return data.models ?? [];
14
+ }
15
+ async function checkOllama() {
16
+ const res = await fetch(`${shared_1.OLLAMA_HOST}/`, {
17
+ signal: AbortSignal.timeout(shared_1.OLLAMA_HEALTH_TIMEOUT_MS),
18
+ });
19
+ if (!res.ok)
20
+ throw new Error(`Ollama health check failed: ${res.status}`);
21
+ }
22
+ //# sourceMappingURL=ollama.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ollama.js","sourceRoot":"","sources":["../../../src/api/services/ollama.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAQb,wCAOC;AAED,kCAKC;AApBD,yCAA6F;AAMtF,KAAK,UAAU,cAAc;IAClC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,oBAAW,WAAW,EAAE;QACjD,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,+BAAsB,CAAC;KACpD,CAAC,CAAC;IACH,IAAI,CAAC,GAAG,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IAClE,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA+B,CAAC;IAC9D,OAAO,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC;AAC3B,CAAC;AAEM,KAAK,UAAU,WAAW;IAC/B,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,oBAAW,GAAG,EAAE;QACzC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,iCAAwB,CAAC;KACtD,CAAC,CAAC;IACH,IAAI,CAAC,GAAG,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;AAC5E,CAAC"}
@@ -0,0 +1,3 @@
1
+ 'use strict';
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/api/types.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC"}
@@ -0,0 +1,78 @@
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
+ exports.setSSEHeaders = setSSEHeaders;
7
+ exports.buildChunk = buildChunk;
8
+ exports.buildCompletion = buildCompletion;
9
+ exports.writeSSE = writeSSE;
10
+ exports.endSSE = endSSE;
11
+ exports.writeSSEError = writeSSEError;
12
+ exports.generateChatId = generateChatId;
13
+ exports.estimateTokens = estimateTokens;
14
+ const crypto_1 = __importDefault(require("crypto"));
15
+ function setSSEHeaders(res) {
16
+ res.setHeader('Content-Type', 'text/event-stream');
17
+ res.setHeader('Cache-Control', 'no-cache');
18
+ res.setHeader('Connection', 'keep-alive');
19
+ res.setHeader('X-Accel-Buffering', 'no');
20
+ }
21
+ function buildChunk(model, content, chatId, finishReason = null) {
22
+ return {
23
+ id: chatId,
24
+ object: 'chat.completion.chunk',
25
+ created: Math.floor(Date.now() / 1000),
26
+ model,
27
+ choices: [
28
+ {
29
+ index: 0,
30
+ delta: content !== null ? { content } : {},
31
+ finish_reason: finishReason,
32
+ },
33
+ ],
34
+ };
35
+ }
36
+ function buildCompletion(model, content, usage) {
37
+ return {
38
+ id: generateChatId(),
39
+ object: 'chat.completion',
40
+ created: Math.floor(Date.now() / 1000),
41
+ model,
42
+ choices: [
43
+ {
44
+ index: 0,
45
+ message: { role: 'assistant', content },
46
+ finish_reason: 'stop',
47
+ },
48
+ ],
49
+ usage: {
50
+ prompt_tokens: usage.tokensIn,
51
+ completion_tokens: usage.tokensOut,
52
+ total_tokens: usage.tokensIn + usage.tokensOut,
53
+ },
54
+ };
55
+ }
56
+ function writeSSE(res, data) {
57
+ res.write(`data: ${JSON.stringify(data)}\n\n`);
58
+ }
59
+ function endSSE(res) {
60
+ res.write('data: [DONE]\n\n');
61
+ res.end();
62
+ }
63
+ function writeSSEError(res, message) {
64
+ res.write(`data: ${JSON.stringify({ error: { message } })}\n\n`);
65
+ endSSE(res);
66
+ }
67
+ function generateChatId() {
68
+ return `chatcmpl-${crypto_1.default.randomBytes(12).toString('base64url')}`;
69
+ }
70
+ function estimateTokens(messages) {
71
+ if (!Array.isArray(messages))
72
+ return 0;
73
+ const totalChars = messages.reduce((sum, m) => {
74
+ return sum + (typeof m.content === 'string' ? m.content.length : 0);
75
+ }, 0);
76
+ return Math.ceil(totalChars / 4);
77
+ }
78
+ //# sourceMappingURL=sse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sse.js","sourceRoot":"","sources":["../../../src/api/utils/sse.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,230 @@
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 fs_1 = __importDefault(require("fs"));
42
+ const child_process_1 = require("child_process");
43
+ const paths = __importStar(require("../utils/paths"));
44
+ const client_1 = require("../../cloud/client");
45
+ async function check(label, fn) {
46
+ try {
47
+ await fn();
48
+ console.log(chalk_1.default.green(` ✔ ${label}`));
49
+ return true;
50
+ }
51
+ catch (e) {
52
+ console.log(chalk_1.default.red(` ✖ ${label}`) + chalk_1.default.gray(` — ${e.message}`));
53
+ return false;
54
+ }
55
+ }
56
+ function readToken() {
57
+ try {
58
+ if (!fs_1.default.existsSync(paths.CONFIG_PATH))
59
+ return null;
60
+ const data = JSON.parse(fs_1.default.readFileSync(paths.CONFIG_PATH, 'utf8'));
61
+ const t = data.token;
62
+ return typeof t === 'string' && t.startsWith('qs_') ? t : null;
63
+ }
64
+ catch {
65
+ return null;
66
+ }
67
+ }
68
+ function getPythonVersion(platform) {
69
+ const candidates = platform === 'win32' ? ['python3', 'python', 'py'] : ['python3'];
70
+ for (const cmd of candidates) {
71
+ try {
72
+ const out = (0, child_process_1.execFileSync)(cmd, ['--version'], {
73
+ encoding: 'utf8',
74
+ stdio: ['ignore', 'pipe', 'pipe'],
75
+ });
76
+ const version = (out || '').trim();
77
+ if (/Python 3\.\d+/.test(version))
78
+ return `${version} (${cmd})`;
79
+ }
80
+ catch {
81
+ /* try next */
82
+ }
83
+ }
84
+ return null;
85
+ }
86
+ function isCommandAvailable(cmd) {
87
+ const which = process.platform === 'win32' ? 'where' : 'which';
88
+ try {
89
+ (0, child_process_1.execFileSync)(which, [cmd], { stdio: 'ignore' });
90
+ return true;
91
+ }
92
+ catch {
93
+ return false;
94
+ }
95
+ }
96
+ const cmd = new commander_1.Command('doctor').description('Run pre-flight checks');
97
+ cmd.action(async () => {
98
+ paths.loadEnv();
99
+ const platform = process.platform;
100
+ const arch = process.arch;
101
+ console.log(chalk_1.default.bold('\n LocoPilot Doctor\n'));
102
+ console.log(chalk_1.default.gray(` Platform: ${platform} / ${arch} / Node.js ${process.version}\n`));
103
+ const results = [];
104
+ // ── Ollama ────────────────────────────────────────────────────────────────
105
+ results.push(await check('Ollama reachable', async () => {
106
+ const host = process.env.OLLAMA_HOST ?? 'http://localhost:11434';
107
+ const res = await fetch(`${host}/`, { signal: AbortSignal.timeout(5_000) });
108
+ if (!res.ok)
109
+ throw new Error(`HTTP ${res.status}`);
110
+ }));
111
+ results.push(await check('Ollama CLI installed', async () => {
112
+ if (!isCommandAvailable('ollama')) {
113
+ const hint = platform === 'darwin'
114
+ ? 'brew install --cask ollama'
115
+ : platform === 'linux'
116
+ ? 'curl -fsSL https://ollama.com/install.sh | sh'
117
+ : 'winget install Ollama.Ollama';
118
+ throw new Error(`Not found — ${hint}`);
119
+ }
120
+ let version = '';
121
+ try {
122
+ version = (0, child_process_1.execFileSync)('ollama', ['--version'], { encoding: 'utf8' }).trim();
123
+ }
124
+ catch {
125
+ /* non-fatal */
126
+ }
127
+ if (version)
128
+ return; // attach version to label
129
+ }));
130
+ // ── Home dir + SQLite ─────────────────────────────────────────────────────
131
+ results.push(await check('Home directory writable', async () => {
132
+ paths.ensureHomeDir();
133
+ const tmp = `${paths.SQLITE_PATH}.tmp`;
134
+ fs_1.default.writeFileSync(tmp, '');
135
+ fs_1.default.unlinkSync(tmp);
136
+ }));
137
+ results.push(await check('SQLite database exists', async () => {
138
+ if (!fs_1.default.existsSync(paths.SQLITE_PATH)) {
139
+ throw new Error('Not found — run: locopilot init');
140
+ }
141
+ const stat = fs_1.default.statSync(paths.SQLITE_PATH);
142
+ if (stat.size === 0)
143
+ throw new Error('Database is empty — run: locopilot init');
144
+ }));
145
+ // ── Disk space ────────────────────────────────────────────────────────────
146
+ results.push(await check('Disk space (> 500 MB free)', async () => {
147
+ // fs.statfsSync added in Node 19.6 / 20.0
148
+ const statfsSync = fs_1.default
149
+ .statfsSync;
150
+ if (typeof statfsSync !== 'function')
151
+ return; // skip on older Node
152
+ const stats = statfsSync(paths.HOME_DIR);
153
+ const freeMB = (stats.bavail * stats.bsize) / (1024 * 1024);
154
+ if (freeMB < 500) {
155
+ throw new Error(`Only ${Math.floor(freeMB)} MB free — models require several GB`);
156
+ }
157
+ }));
158
+ // ── Python 3 (for training adapters) ─────────────────────────────────────
159
+ console.log('');
160
+ results.push(await check('Python 3 (for training adapters)', async () => {
161
+ const version = getPythonVersion(platform);
162
+ if (!version) {
163
+ const hint = platform === 'darwin'
164
+ ? 'brew install python3'
165
+ : platform === 'win32'
166
+ ? 'https://www.python.org/downloads/'
167
+ : 'sudo apt install python3';
168
+ throw new Error(`Not found — ${hint}`);
169
+ }
170
+ }));
171
+ // ── Training adapter hint ─────────────────────────────────────────────────
172
+ if (platform === 'darwin' && arch === 'arm64') {
173
+ const mlxOk = await check('MLX adapter (mlx-lm)', async () => {
174
+ (0, child_process_1.execFileSync)('python3', ['-c', 'import mlx_lm'], {
175
+ stdio: ['ignore', 'ignore', 'pipe'],
176
+ });
177
+ });
178
+ if (!mlxOk) {
179
+ console.log(chalk_1.default.gray(' Install: pip3 install mlx-lm'));
180
+ }
181
+ }
182
+ else {
183
+ const unslothOk = await check('Unsloth adapter', async () => {
184
+ const py = platform === 'win32' ? 'python' : 'python3';
185
+ (0, child_process_1.execFileSync)(py, ['-c', 'import unsloth'], { stdio: ['ignore', 'ignore', 'pipe'] });
186
+ });
187
+ if (!unslothOk) {
188
+ console.log(chalk_1.default.gray(' Install: pip3 install unsloth trl transformers datasets'));
189
+ }
190
+ }
191
+ // ── API server ────────────────────────────────────────────────────────────
192
+ console.log('');
193
+ results.push(await check('Local API server reachable', async () => {
194
+ const port = process.env.API_PORT ?? '8080';
195
+ const res = await fetch(`http://localhost:${port}/v1/locopilot/health`, {
196
+ signal: AbortSignal.timeout(3_000),
197
+ });
198
+ if (!res.ok)
199
+ throw new Error(`HTTP ${res.status}`);
200
+ }));
201
+ // ── Pro-tier checks ───────────────────────────────────────────────────────
202
+ console.log('');
203
+ const token = readToken();
204
+ if (!token) {
205
+ console.log(chalk_1.default.gray(' Pro: not logged in — run `locopilot login` to enable cloud features'));
206
+ }
207
+ else {
208
+ results.push(await check('(Pro) LocoPilot Cloud reachable', async () => {
209
+ const res = await (0, client_1.callCloudAuthVerify)(`Bearer ${token}`);
210
+ if (res.status === 401)
211
+ throw new Error('Invalid API key — run: locopilot login');
212
+ if (!res.ok)
213
+ throw new Error(`Cloud returned HTTP ${res.status}`);
214
+ }));
215
+ }
216
+ // ── Summary ───────────────────────────────────────────────────────────────
217
+ console.log('');
218
+ const allOk = results.every(Boolean);
219
+ if (allOk) {
220
+ const mode = token ? 'Pro' : 'Free';
221
+ console.log(chalk_1.default.green.bold(` ${mode} tier ready.\n`));
222
+ }
223
+ else {
224
+ const failCount = results.filter((r) => !r).length;
225
+ console.log(chalk_1.default.yellow.bold(` ${failCount} check(s) failed. Fix the issues above and retry.\n`));
226
+ process.exitCode = 1;
227
+ }
228
+ });
229
+ exports.default = cmd;
230
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"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"}