@paparats/cli 0.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.
- package/LICENSE +21 -0
- package/README.md +33 -0
- package/bin/paparats +2 -0
- package/dist/abort.d.ts +6 -0
- package/dist/abort.d.ts.map +1 -0
- package/dist/abort.js +13 -0
- package/dist/abort.js.map +1 -0
- package/dist/api-client.d.ts +69 -0
- package/dist/api-client.d.ts.map +1 -0
- package/dist/api-client.js +188 -0
- package/dist/api-client.js.map +1 -0
- package/dist/commands/doctor.d.ts +10 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +239 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/groups.d.ts +47 -0
- package/dist/commands/groups.d.ts.map +1 -0
- package/dist/commands/groups.js +197 -0
- package/dist/commands/groups.js.map +1 -0
- package/dist/commands/index-cmd.d.ts +75 -0
- package/dist/commands/index-cmd.d.ts.map +1 -0
- package/dist/commands/index-cmd.js +240 -0
- package/dist/commands/index-cmd.js.map +1 -0
- package/dist/commands/init.d.ts +28 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +437 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/install.d.ts +41 -0
- package/dist/commands/install.d.ts.map +1 -0
- package/dist/commands/install.js +324 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/search.d.ts +53 -0
- package/dist/commands/search.d.ts.map +1 -0
- package/dist/commands/search.js +216 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/status.d.ts +69 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +309 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/update.d.ts +18 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +95 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/watch.d.ts +31 -0
- package/dist/commands/watch.d.ts.map +1 -0
- package/dist/commands/watch.js +339 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/config.d.ts +46 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +308 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/lsp-installers.d.ts +28 -0
- package/dist/lsp-installers.d.ts.map +1 -0
- package/dist/lsp-installers.js +125 -0
- package/dist/lsp-installers.js.map +1 -0
- package/package.json +81 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ilya Bazylchuk
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# @paparats/cli
|
|
2
|
+
|
|
3
|
+
CLI for [Paparats MCP](https://github.com/IBazylchuk/paparats-mcp) — semantic code search across multiple repositories. MCP server powered by Qdrant vector search and Ollama embeddings, designed for AI coding assistants (Claude Code, Cursor).
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @paparats/cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Prerequisites
|
|
12
|
+
|
|
13
|
+
- **Docker** + **Docker Compose** — runs Qdrant and MCP server
|
|
14
|
+
- **Ollama** — local embedding model (on host)
|
|
15
|
+
|
|
16
|
+
## Quick start
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# 1. Ensure Docker, Docker Compose, and Ollama are installed
|
|
20
|
+
docker --version && docker compose version && ollama --version
|
|
21
|
+
|
|
22
|
+
# 2. One-time setup: starts Qdrant + MCP server, downloads GGUF (~1.6 GB)
|
|
23
|
+
paparats install
|
|
24
|
+
|
|
25
|
+
# 3. In your project
|
|
26
|
+
cd your-project
|
|
27
|
+
paparats init # creates .paparats.yml
|
|
28
|
+
paparats index # index the codebase
|
|
29
|
+
|
|
30
|
+
# 4. Connect your IDE (Cursor, Claude Code) to the MCP server
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
See the [full documentation](https://github.com/IBazylchuk/paparats-mcp#readme) for MCP setup and configuration.
|
package/bin/paparats
ADDED
package/dist/abort.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns an AbortSignal that aborts after the given timeout.
|
|
3
|
+
* Uses AbortSignal.timeout() when available (Node 18+), otherwise falls back to AbortController.
|
|
4
|
+
*/
|
|
5
|
+
export declare function createTimeoutSignal(timeoutMs: number): AbortSignal;
|
|
6
|
+
//# sourceMappingURL=abort.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abort.d.ts","sourceRoot":"","sources":["../src/abort.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,CAOlE"}
|
package/dist/abort.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns an AbortSignal that aborts after the given timeout.
|
|
3
|
+
* Uses AbortSignal.timeout() when available (Node 18+), otherwise falls back to AbortController.
|
|
4
|
+
*/
|
|
5
|
+
export function createTimeoutSignal(timeoutMs) {
|
|
6
|
+
if ('timeout' in AbortSignal && typeof AbortSignal.timeout === 'function') {
|
|
7
|
+
return AbortSignal.timeout(timeoutMs);
|
|
8
|
+
}
|
|
9
|
+
const controller = new AbortController();
|
|
10
|
+
setTimeout(() => controller.abort(), timeoutMs);
|
|
11
|
+
return controller.signal;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=abort.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abort.js","sourceRoot":"","sources":["../src/abort.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,SAAiB;IACnD,IAAI,SAAS,IAAI,WAAW,IAAI,OAAO,WAAW,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;QAC1E,OAAO,WAAW,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACxC,CAAC;IACD,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;IACzC,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,SAAS,CAAC,CAAC;IAChD,OAAO,UAAU,CAAC,MAAM,CAAC;AAC3B,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
interface RequestOptions {
|
|
2
|
+
method: 'GET' | 'POST';
|
|
3
|
+
path: string;
|
|
4
|
+
body?: unknown;
|
|
5
|
+
timeout?: number;
|
|
6
|
+
signal?: AbortSignal;
|
|
7
|
+
}
|
|
8
|
+
export interface IndexConfig {
|
|
9
|
+
chunkSize?: number;
|
|
10
|
+
overlap?: number;
|
|
11
|
+
batchSize?: number;
|
|
12
|
+
concurrency?: number;
|
|
13
|
+
languages?: string[];
|
|
14
|
+
}
|
|
15
|
+
export interface IndexFile {
|
|
16
|
+
path: string;
|
|
17
|
+
content: string;
|
|
18
|
+
language?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface ApiClientOptions {
|
|
21
|
+
baseUrl?: string;
|
|
22
|
+
defaultTimeout?: number;
|
|
23
|
+
maxRetries?: number;
|
|
24
|
+
debug?: boolean;
|
|
25
|
+
}
|
|
26
|
+
interface ApiResponse<T = unknown> {
|
|
27
|
+
status: number;
|
|
28
|
+
data: T;
|
|
29
|
+
}
|
|
30
|
+
export declare class ApiClient {
|
|
31
|
+
private baseUrl;
|
|
32
|
+
private defaultTimeout;
|
|
33
|
+
private maxRetries;
|
|
34
|
+
private debug;
|
|
35
|
+
constructor(options?: ApiClientOptions | string);
|
|
36
|
+
private log;
|
|
37
|
+
request<T = unknown>(options: RequestOptions): Promise<ApiResponse<T>>;
|
|
38
|
+
private requestWithRetry;
|
|
39
|
+
search(group: string, query: string, options?: {
|
|
40
|
+
project?: string;
|
|
41
|
+
limit?: number;
|
|
42
|
+
timeout?: number;
|
|
43
|
+
signal?: AbortSignal;
|
|
44
|
+
}): Promise<ApiResponse>;
|
|
45
|
+
/** Content-based index: send group, project, config, and files with content */
|
|
46
|
+
indexContent(group: string, project: string, files: IndexFile[], options?: {
|
|
47
|
+
config?: IndexConfig;
|
|
48
|
+
force?: boolean;
|
|
49
|
+
timeout?: number;
|
|
50
|
+
signal?: AbortSignal;
|
|
51
|
+
}): Promise<ApiResponse>;
|
|
52
|
+
fileChanged(group: string, project: string, path: string, content: string, options?: {
|
|
53
|
+
language?: string;
|
|
54
|
+
timeout?: number;
|
|
55
|
+
signal?: AbortSignal;
|
|
56
|
+
}): Promise<ApiResponse>;
|
|
57
|
+
fileDeleted(group: string, project: string, path: string, options?: {
|
|
58
|
+
timeout?: number;
|
|
59
|
+
signal?: AbortSignal;
|
|
60
|
+
}): Promise<ApiResponse>;
|
|
61
|
+
health(options?: {
|
|
62
|
+
timeout?: number;
|
|
63
|
+
}): Promise<ApiResponse>;
|
|
64
|
+
stats(options?: {
|
|
65
|
+
timeout?: number;
|
|
66
|
+
}): Promise<ApiResponse>;
|
|
67
|
+
}
|
|
68
|
+
export {};
|
|
69
|
+
//# sourceMappingURL=api-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import http from 'node:http';
|
|
2
|
+
import https from 'node:https';
|
|
3
|
+
const DEFAULT_BASE_URL = 'http://localhost:9876';
|
|
4
|
+
const MAX_RESPONSE_SIZE = 100 * 1024 * 1024; // 100MB
|
|
5
|
+
function formatConnectionError(err, baseUrl) {
|
|
6
|
+
if (err.code === 'ABORT_ERR' || err.name === 'AbortError') {
|
|
7
|
+
return 'Request aborted';
|
|
8
|
+
}
|
|
9
|
+
let message = `Failed to connect to ${baseUrl}`;
|
|
10
|
+
switch (err.code) {
|
|
11
|
+
case 'ECONNREFUSED':
|
|
12
|
+
message += ' - Connection refused. Is the server running?';
|
|
13
|
+
break;
|
|
14
|
+
case 'ENOTFOUND':
|
|
15
|
+
message += ' - Host not found. Check the URL.';
|
|
16
|
+
break;
|
|
17
|
+
case 'ETIMEDOUT':
|
|
18
|
+
message += ' - Connection timed out.';
|
|
19
|
+
break;
|
|
20
|
+
case 'ECONNRESET':
|
|
21
|
+
message += ' - Connection reset by server.';
|
|
22
|
+
break;
|
|
23
|
+
default:
|
|
24
|
+
message += ` - ${err.message}`;
|
|
25
|
+
}
|
|
26
|
+
return message;
|
|
27
|
+
}
|
|
28
|
+
export class ApiClient {
|
|
29
|
+
baseUrl;
|
|
30
|
+
defaultTimeout;
|
|
31
|
+
maxRetries;
|
|
32
|
+
debug;
|
|
33
|
+
constructor(options) {
|
|
34
|
+
const opts = typeof options === 'string' ? { baseUrl: options } : (options ?? {});
|
|
35
|
+
this.baseUrl = opts.baseUrl ?? DEFAULT_BASE_URL;
|
|
36
|
+
this.defaultTimeout = opts.defaultTimeout ?? 120_000;
|
|
37
|
+
this.maxRetries = opts.maxRetries ?? 3;
|
|
38
|
+
this.debug = opts.debug ?? false;
|
|
39
|
+
try {
|
|
40
|
+
new URL(this.baseUrl);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
throw new Error(`Invalid base URL: ${this.baseUrl}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
log(message, data) {
|
|
47
|
+
if (this.debug) {
|
|
48
|
+
console.error(`[ApiClient] ${message}`, data ?? '');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async request(options) {
|
|
52
|
+
const url = new URL(options.path, this.baseUrl);
|
|
53
|
+
const payload = options.body ? JSON.stringify(options.body) : undefined;
|
|
54
|
+
const client = url.protocol === 'https:' ? https : http;
|
|
55
|
+
const timeout = options.timeout ?? this.defaultTimeout;
|
|
56
|
+
this.log(`${options.method} ${url.href}`, options.body);
|
|
57
|
+
return new Promise((resolve, reject) => {
|
|
58
|
+
const req = client.request(url, {
|
|
59
|
+
method: options.method,
|
|
60
|
+
headers: {
|
|
61
|
+
'Content-Type': 'application/json',
|
|
62
|
+
...(payload && { 'Content-Length': Buffer.byteLength(payload) }),
|
|
63
|
+
},
|
|
64
|
+
timeout,
|
|
65
|
+
...(options.signal && { signal: options.signal }),
|
|
66
|
+
}, (res) => {
|
|
67
|
+
const chunks = [];
|
|
68
|
+
let totalLength = 0;
|
|
69
|
+
res.on('data', (chunk) => {
|
|
70
|
+
chunks.push(chunk);
|
|
71
|
+
totalLength += chunk.length;
|
|
72
|
+
if (totalLength > MAX_RESPONSE_SIZE) {
|
|
73
|
+
req.destroy();
|
|
74
|
+
reject(new Error('Response too large (>100MB)'));
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
res.on('end', () => {
|
|
78
|
+
try {
|
|
79
|
+
const body = Buffer.concat(chunks).toString('utf-8');
|
|
80
|
+
const data = body ? JSON.parse(body) : {};
|
|
81
|
+
const status = res.statusCode ?? 500;
|
|
82
|
+
this.log(`Response: ${status}`);
|
|
83
|
+
if (status >= 400) {
|
|
84
|
+
const errorMsg = data?.error ?? `HTTP ${status} error`;
|
|
85
|
+
reject(new Error(`HTTP ${status}: ${errorMsg}`));
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
resolve({ status, data });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
const body = Buffer.concat(chunks).toString('utf-8');
|
|
93
|
+
reject(new Error(`Invalid JSON response: ${body.slice(0, 200)}`));
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
req.on('error', (err) => {
|
|
98
|
+
reject(new Error(formatConnectionError(err, this.baseUrl)));
|
|
99
|
+
});
|
|
100
|
+
req.on('timeout', () => {
|
|
101
|
+
req.destroy();
|
|
102
|
+
reject(new Error(`Request timed out after ${timeout}ms`));
|
|
103
|
+
});
|
|
104
|
+
if (payload)
|
|
105
|
+
req.write(payload);
|
|
106
|
+
req.end();
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
async requestWithRetry(options, skipRetry) {
|
|
110
|
+
let lastError;
|
|
111
|
+
for (let attempt = 0; attempt < (skipRetry ? 1 : this.maxRetries); attempt++) {
|
|
112
|
+
try {
|
|
113
|
+
return await this.request(options);
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
lastError = err;
|
|
117
|
+
if (skipRetry)
|
|
118
|
+
throw lastError;
|
|
119
|
+
const msg = lastError.message;
|
|
120
|
+
if (msg.includes('HTTP 4') ||
|
|
121
|
+
msg.includes('Invalid JSON') ||
|
|
122
|
+
msg.includes('Response too large')) {
|
|
123
|
+
throw lastError;
|
|
124
|
+
}
|
|
125
|
+
if (attempt < this.maxRetries - 1) {
|
|
126
|
+
const delay = Math.min(1000 * Math.pow(2, attempt), 10_000);
|
|
127
|
+
this.log(`Retry ${attempt + 1}/${this.maxRetries} after ${delay}ms...`);
|
|
128
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
throw lastError ?? new Error('Request failed');
|
|
133
|
+
}
|
|
134
|
+
async search(group, query, options) {
|
|
135
|
+
return this.requestWithRetry({
|
|
136
|
+
method: 'POST',
|
|
137
|
+
path: '/api/search',
|
|
138
|
+
body: { group, query, project: options?.project ?? 'all', limit: options?.limit ?? 5 },
|
|
139
|
+
timeout: options?.timeout ?? 30_000,
|
|
140
|
+
signal: options?.signal,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
/** Content-based index: send group, project, config, and files with content */
|
|
144
|
+
async indexContent(group, project, files, options) {
|
|
145
|
+
return this.requestWithRetry({
|
|
146
|
+
method: 'POST',
|
|
147
|
+
path: '/api/index',
|
|
148
|
+
body: {
|
|
149
|
+
group,
|
|
150
|
+
project,
|
|
151
|
+
config: options?.config,
|
|
152
|
+
files,
|
|
153
|
+
...(options?.force && { force: true }),
|
|
154
|
+
},
|
|
155
|
+
timeout: options?.timeout ?? 300_000,
|
|
156
|
+
signal: options?.signal,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
async fileChanged(group, project, path, content, options) {
|
|
160
|
+
return this.requestWithRetry({
|
|
161
|
+
method: 'POST',
|
|
162
|
+
path: '/api/file-changed',
|
|
163
|
+
body: { group, project, path, content, language: options?.language },
|
|
164
|
+
timeout: options?.timeout ?? 60_000,
|
|
165
|
+
signal: options?.signal,
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
async fileDeleted(group, project, path, options) {
|
|
169
|
+
return this.requestWithRetry({
|
|
170
|
+
method: 'POST',
|
|
171
|
+
path: '/api/file-deleted',
|
|
172
|
+
body: { group, project, path },
|
|
173
|
+
timeout: options?.timeout ?? 60_000,
|
|
174
|
+
signal: options?.signal,
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
async health(options) {
|
|
178
|
+
return this.request({ method: 'GET', path: '/health', timeout: options?.timeout ?? 5_000 });
|
|
179
|
+
}
|
|
180
|
+
async stats(options) {
|
|
181
|
+
return this.request({
|
|
182
|
+
method: 'GET',
|
|
183
|
+
path: '/api/stats',
|
|
184
|
+
timeout: options?.timeout ?? 10_000,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=api-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,KAAK,MAAM,YAAY,CAAC;AAE/B,MAAM,gBAAgB,GAAG,uBAAuB,CAAC;AACjD,MAAM,iBAAiB,GAAG,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,QAAQ;AAoCrD,SAAS,qBAAqB,CAAC,GAA0B,EAAE,OAAe;IACxE,IAAI,GAAG,CAAC,IAAI,KAAK,WAAW,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QAC1D,OAAO,iBAAiB,CAAC;IAC3B,CAAC;IAED,IAAI,OAAO,GAAG,wBAAwB,OAAO,EAAE,CAAC;IAEhD,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;QACjB,KAAK,cAAc;YACjB,OAAO,IAAI,+CAA+C,CAAC;YAC3D,MAAM;QACR,KAAK,WAAW;YACd,OAAO,IAAI,mCAAmC,CAAC;YAC/C,MAAM;QACR,KAAK,WAAW;YACd,OAAO,IAAI,0BAA0B,CAAC;YACtC,MAAM;QACR,KAAK,YAAY;YACf,OAAO,IAAI,gCAAgC,CAAC;YAC5C,MAAM;QACR;YACE,OAAO,IAAI,MAAM,GAAG,CAAC,OAAO,EAAE,CAAC;IACnC,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,OAAO,SAAS;IACZ,OAAO,CAAS;IAChB,cAAc,CAAS;IACvB,UAAU,CAAS;IACnB,KAAK,CAAU;IAEvB,YAAY,OAAmC;QAC7C,MAAM,IAAI,GAAG,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;QAClF,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,gBAAgB,CAAC;QAChD,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,cAAc,IAAI,OAAO,CAAC;QACrD,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,CAAC,CAAC;QACvC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC;QAEjC,IAAI,CAAC;YACH,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CAAC,qBAAqB,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IAEO,GAAG,CAAC,OAAe,EAAE,IAAc;QACzC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,eAAe,OAAO,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC;QACtD,CAAC;IACH,CAAC;IAED,KAAK,CAAC,OAAO,CAAc,OAAuB;QAChD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QAChD,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACxE,MAAM,MAAM,GAAG,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;QACxD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,IAAI,CAAC,cAAc,CAAC;QAEvD,IAAI,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,IAAI,GAAG,CAAC,IAAI,EAAE,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QAExD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACrC,MAAM,GAAG,GAAG,MAAM,CAAC,OAAO,CACxB,GAAG,EACH;gBACE,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;oBAClC,GAAG,CAAC,OAAO,IAAI,EAAE,gBAAgB,EAAE,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;iBACjE;gBACD,OAAO;gBACP,GAAG,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;aAClD,EACD,CAAC,GAAG,EAAE,EAAE;gBACN,MAAM,MAAM,GAAa,EAAE,CAAC;gBAC5B,IAAI,WAAW,GAAG,CAAC,CAAC;gBAEpB,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;oBAC/B,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oBACnB,WAAW,IAAI,KAAK,CAAC,MAAM,CAAC;oBAE5B,IAAI,WAAW,GAAG,iBAAiB,EAAE,CAAC;wBACpC,GAAG,CAAC,OAAO,EAAE,CAAC;wBACd,MAAM,CAAC,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC,CAAC;oBACnD,CAAC;gBACH,CAAC,CAAC,CAAC;gBAEH,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;oBACjB,IAAI,CAAC;wBACH,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;wBACrD,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAO,CAAC,CAAC,CAAE,EAAQ,CAAC;wBACxD,MAAM,MAAM,GAAG,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC;wBAErC,IAAI,CAAC,GAAG,CAAC,aAAa,MAAM,EAAE,CAAC,CAAC;wBAEhC,IAAI,MAAM,IAAI,GAAG,EAAE,CAAC;4BAClB,MAAM,QAAQ,GAAI,IAA2B,EAAE,KAAK,IAAI,QAAQ,MAAM,QAAQ,CAAC;4BAC/E,MAAM,CAAC,IAAI,KAAK,CAAC,QAAQ,MAAM,KAAK,QAAQ,EAAE,CAAC,CAAC,CAAC;wBACnD,CAAC;6BAAM,CAAC;4BACN,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;wBAC5B,CAAC;oBACH,CAAC;oBAAC,MAAM,CAAC;wBACP,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;wBACrD,MAAM,CAAC,IAAI,KAAK,CAAC,0BAA0B,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;oBACpE,CAAC;gBACH,CAAC,CAAC,CAAC;YACL,CAAC,CACF,CAAC;YAEF,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAA0B,EAAE,EAAE;gBAC7C,MAAM,CAAC,IAAI,KAAK,CAAC,qBAAqB,CAAC,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YAC9D,CAAC,CAAC,CAAC;YAEH,GAAG,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;gBACrB,GAAG,CAAC,OAAO,EAAE,CAAC;gBACd,MAAM,CAAC,IAAI,KAAK,CAAC,2BAA2B,OAAO,IAAI,CAAC,CAAC,CAAC;YAC5D,CAAC,CAAC,CAAC;YAEH,IAAI,OAAO;gBAAE,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YAChC,GAAG,CAAC,GAAG,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAC5B,OAAuB,EACvB,SAAmB;QAEnB,IAAI,SAA4B,CAAC;QAEjC,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,EAAE,CAAC;YAC7E,IAAI,CAAC;gBACH,OAAO,MAAM,IAAI,CAAC,OAAO,CAAI,OAAO,CAAC,CAAC;YACxC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,SAAS,GAAG,GAAY,CAAC;gBAEzB,IAAI,SAAS;oBAAE,MAAM,SAAS,CAAC;gBAE/B,MAAM,GAAG,GAAG,SAAS,CAAC,OAAO,CAAC;gBAC9B,IACE,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC;oBACtB,GAAG,CAAC,QAAQ,CAAC,cAAc,CAAC;oBAC5B,GAAG,CAAC,QAAQ,CAAC,oBAAoB,CAAC,EAClC,CAAC;oBACD,MAAM,SAAS,CAAC;gBAClB,CAAC;gBAED,IAAI,OAAO,GAAG,IAAI,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC;oBAClC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,CAAC;oBAC5D,IAAI,CAAC,GAAG,CAAC,SAAS,OAAO,GAAG,CAAC,IAAI,IAAI,CAAC,UAAU,UAAU,KAAK,OAAO,CAAC,CAAC;oBACxE,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;gBACjD,CAAC;YACH,CAAC;QACH,CAAC;QAED,MAAM,SAAS,IAAI,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;IACjD,CAAC;IAED,KAAK,CAAC,MAAM,CACV,KAAa,EACb,KAAa,EACb,OAAsF;QAEtF,OAAO,IAAI,CAAC,gBAAgB,CAAC;YAC3B,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,aAAa;YACnB,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC,EAAE;YACtF,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,MAAM;YACnC,MAAM,EAAE,OAAO,EAAE,MAAM;SACxB,CAAC,CAAC;IACL,CAAC;IAED,+EAA+E;IAC/E,KAAK,CAAC,YAAY,CAChB,KAAa,EACb,OAAe,EACf,KAAkB,EAClB,OAKC;QAED,OAAO,IAAI,CAAC,gBAAgB,CAAC;YAC3B,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,YAAY;YAClB,IAAI,EAAE;gBACJ,KAAK;gBACL,OAAO;gBACP,MAAM,EAAE,OAAO,EAAE,MAAM;gBACvB,KAAK;gBACL,GAAG,CAAC,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;aACvC;YACD,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,OAAO;YACpC,MAAM,EAAE,OAAO,EAAE,MAAM;SACxB,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,WAAW,CACf,KAAa,EACb,OAAe,EACf,IAAY,EACZ,OAAe,EACf,OAAuE;QAEvE,OAAO,IAAI,CAAC,gBAAgB,CAAC;YAC3B,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,mBAAmB;YACzB,IAAI,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE;YACpE,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,MAAM;YACnC,MAAM,EAAE,OAAO,EAAE,MAAM;SACxB,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,WAAW,CACf,KAAa,EACb,OAAe,EACf,IAAY,EACZ,OAAoD;QAEpD,OAAO,IAAI,CAAC,gBAAgB,CAAC;YAC3B,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,mBAAmB;YACzB,IAAI,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE;YAC9B,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,MAAM;YACnC,MAAM,EAAE,OAAO,EAAE,MAAM;SACxB,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,OAA8B;QACzC,OAAO,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,CAAC,CAAC;IAC9F,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,OAA8B;QACxC,OAAO,IAAI,CAAC,OAAO,CAAC;YAClB,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,YAAY;YAClB,OAAO,EAAE,OAAO,EAAE,OAAO,IAAI,MAAM;SACpC,CAAC,CAAC;IACL,CAAC;CACF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
export interface CheckResult {
|
|
3
|
+
name: string;
|
|
4
|
+
ok: boolean;
|
|
5
|
+
message: string;
|
|
6
|
+
details?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function runChecks(serverUrl: string, onCheckStart?: (name: string) => void, verbose?: boolean): Promise<CheckResult[]>;
|
|
9
|
+
export declare const doctorCommand: Command;
|
|
10
|
+
//# sourceMappingURL=doctor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAyBD,wBAAsB,SAAS,CAC7B,SAAS,EAAE,MAAM,EACjB,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,EACrC,OAAO,CAAC,EAAE,OAAO,GAChB,OAAO,CAAC,WAAW,EAAE,CAAC,CAuKxB;AAED,eAAO,MAAM,aAAa,SAuCtB,CAAC"}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import { execSync } from 'child_process';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import os from 'os';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import ora from 'ora';
|
|
8
|
+
import { findConfigDir, readConfig, CONFIG_FILE } from '../config.js';
|
|
9
|
+
import { ApiClient } from '../api-client.js';
|
|
10
|
+
import { createTimeoutSignal } from '../abort.js';
|
|
11
|
+
function commandExists(cmd) {
|
|
12
|
+
try {
|
|
13
|
+
const command = process.platform === 'win32' ? `where ${cmd}` : `command -v ${cmd}`;
|
|
14
|
+
execSync(command, { stdio: 'ignore', timeout: 3000 });
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function checkDockerCompose() {
|
|
22
|
+
if (commandExists('docker-compose'))
|
|
23
|
+
return true;
|
|
24
|
+
if (commandExists('docker')) {
|
|
25
|
+
try {
|
|
26
|
+
execSync('docker compose version', { stdio: 'ignore', timeout: 3000 });
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
export async function runChecks(serverUrl, onCheckStart, verbose) {
|
|
36
|
+
const results = [];
|
|
37
|
+
// Resolve config for URLs/models
|
|
38
|
+
const qdrantUrl = process.env.QDRANT_URL ?? 'http://localhost:6333';
|
|
39
|
+
const ollamaUrl = process.env.OLLAMA_URL ?? 'http://localhost:11434';
|
|
40
|
+
let ollamaModel = process.env.EMBEDDING_MODEL ?? 'jina-code-embeddings';
|
|
41
|
+
const configDir = findConfigDir();
|
|
42
|
+
if (configDir) {
|
|
43
|
+
try {
|
|
44
|
+
const { config } = readConfig(configDir);
|
|
45
|
+
ollamaModel = config.embeddings?.model ?? ollamaModel;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// Config invalid, use defaults
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// 1. Config (instant)
|
|
52
|
+
onCheckStart?.('Config');
|
|
53
|
+
if (configDir) {
|
|
54
|
+
try {
|
|
55
|
+
readConfig(configDir);
|
|
56
|
+
results.push({ name: CONFIG_FILE, ok: true, message: `found in ${configDir}` });
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
results.push({
|
|
60
|
+
name: CONFIG_FILE,
|
|
61
|
+
ok: false,
|
|
62
|
+
message: err.message,
|
|
63
|
+
details: verbose ? err.stack : undefined,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
results.push({
|
|
69
|
+
name: CONFIG_FILE,
|
|
70
|
+
ok: false,
|
|
71
|
+
message: 'not found in current directory or parents',
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
// 2. Install (instant)
|
|
75
|
+
onCheckStart?.('Install');
|
|
76
|
+
const paparatsHome = path.join(os.homedir(), '.paparats');
|
|
77
|
+
const composePath = path.join(paparatsHome, 'docker-compose.yml');
|
|
78
|
+
if (fs.existsSync(composePath)) {
|
|
79
|
+
results.push({ name: 'Install', ok: true, message: `${composePath} exists` });
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
results.push({
|
|
83
|
+
name: 'Install',
|
|
84
|
+
ok: false,
|
|
85
|
+
message: `${composePath} missing — run \`paparats install\``,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
// 3. Docker
|
|
89
|
+
onCheckStart?.('Docker');
|
|
90
|
+
if (commandExists('docker')) {
|
|
91
|
+
try {
|
|
92
|
+
execSync('docker version', { stdio: 'ignore', timeout: 3_000 });
|
|
93
|
+
results.push({ name: 'Docker', ok: true, message: 'installed and running' });
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
results.push({ name: 'Docker', ok: false, message: 'installed but not running' });
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
results.push({ name: 'Docker', ok: false, message: 'not installed' });
|
|
101
|
+
}
|
|
102
|
+
// 4. Docker Compose
|
|
103
|
+
onCheckStart?.('Docker Compose');
|
|
104
|
+
if (checkDockerCompose()) {
|
|
105
|
+
results.push({ name: 'Docker Compose', ok: true, message: 'installed' });
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
results.push({
|
|
109
|
+
name: 'Docker Compose',
|
|
110
|
+
ok: false,
|
|
111
|
+
message: 'not installed — run `docker compose version` to verify',
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
// 5. Ollama
|
|
115
|
+
onCheckStart?.('Ollama');
|
|
116
|
+
if (commandExists('ollama')) {
|
|
117
|
+
try {
|
|
118
|
+
const ollamaTagsUrl = new URL('/api/tags', ollamaUrl).href;
|
|
119
|
+
const res = await fetch(ollamaTagsUrl, {
|
|
120
|
+
signal: createTimeoutSignal(3000),
|
|
121
|
+
});
|
|
122
|
+
if (res.ok) {
|
|
123
|
+
const data = (await res.json());
|
|
124
|
+
const models = data.models ?? [];
|
|
125
|
+
const hasModel = models.some((m) => m.name.includes(ollamaModel));
|
|
126
|
+
if (hasModel) {
|
|
127
|
+
results.push({ name: 'Ollama', ok: true, message: `model ${ollamaModel} ready` });
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
const available = models.map((m) => m.name).join(', ') || 'none';
|
|
131
|
+
results.push({
|
|
132
|
+
name: 'Ollama',
|
|
133
|
+
ok: false,
|
|
134
|
+
message: `running but ${ollamaModel} model not found`,
|
|
135
|
+
details: verbose ? `Available: ${available}` : undefined,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
const output = execSync('ollama list', { encoding: 'utf8', timeout: 5_000 });
|
|
141
|
+
if (output.includes(ollamaModel)) {
|
|
142
|
+
results.push({ name: 'Ollama', ok: true, message: `model ${ollamaModel} ready` });
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
results.push({
|
|
146
|
+
name: 'Ollama',
|
|
147
|
+
ok: false,
|
|
148
|
+
message: `running but ${ollamaModel} model not found`,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
catch (err) {
|
|
154
|
+
results.push({
|
|
155
|
+
name: 'Ollama',
|
|
156
|
+
ok: false,
|
|
157
|
+
message: 'installed but not running',
|
|
158
|
+
details: verbose ? err.message : undefined,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
results.push({ name: 'Ollama', ok: false, message: 'not installed' });
|
|
164
|
+
}
|
|
165
|
+
// 6. Qdrant
|
|
166
|
+
onCheckStart?.('Qdrant');
|
|
167
|
+
try {
|
|
168
|
+
const qdrantHealthUrl = new URL('/healthz', qdrantUrl).href;
|
|
169
|
+
const res = await fetch(qdrantHealthUrl, {
|
|
170
|
+
signal: createTimeoutSignal(3000),
|
|
171
|
+
});
|
|
172
|
+
results.push({
|
|
173
|
+
name: 'Qdrant',
|
|
174
|
+
ok: res.ok,
|
|
175
|
+
message: res.ok ? `reachable at ${qdrantUrl}` : `status ${res.status}`,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
results.push({
|
|
180
|
+
name: 'Qdrant',
|
|
181
|
+
ok: false,
|
|
182
|
+
message: `unreachable at ${qdrantUrl}`,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
// 7. MCP Server
|
|
186
|
+
onCheckStart?.('MCP Server');
|
|
187
|
+
const client = new ApiClient(serverUrl);
|
|
188
|
+
try {
|
|
189
|
+
const res = await client.health({ timeout: 5000 });
|
|
190
|
+
if (res.status === 200) {
|
|
191
|
+
results.push({ name: 'MCP Server', ok: true, message: 'reachable and healthy' });
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
results.push({ name: 'MCP Server', ok: false, message: `status ${res.status}` });
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
catch {
|
|
198
|
+
results.push({
|
|
199
|
+
name: 'MCP Server',
|
|
200
|
+
ok: false,
|
|
201
|
+
message: `unreachable at ${serverUrl}`,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
return results;
|
|
205
|
+
}
|
|
206
|
+
export const doctorCommand = new Command('doctor')
|
|
207
|
+
.description('Run diagnostic checks')
|
|
208
|
+
.option('--server <url>', 'MCP server URL', 'http://localhost:9876')
|
|
209
|
+
.option('-v, --verbose', 'Show detailed error messages')
|
|
210
|
+
.action(async (opts) => {
|
|
211
|
+
console.log(chalk.bold('\npaparats doctor\n'));
|
|
212
|
+
const spinner = ora('Running diagnostic checks...').start();
|
|
213
|
+
const results = await runChecks(opts.server, (name) => {
|
|
214
|
+
if (opts.verbose) {
|
|
215
|
+
spinner.text = `Checking ${name}...`;
|
|
216
|
+
}
|
|
217
|
+
}, opts.verbose);
|
|
218
|
+
spinner.stop();
|
|
219
|
+
let allOk = true;
|
|
220
|
+
for (const r of results) {
|
|
221
|
+
const icon = r.ok ? chalk.green('✓') : chalk.red('✗');
|
|
222
|
+
const msg = r.ok ? chalk.green(r.message) : chalk.red(r.message);
|
|
223
|
+
console.log(` ${icon} ${chalk.bold(r.name)}: ${msg}`);
|
|
224
|
+
if (r.details) {
|
|
225
|
+
console.log(chalk.gray(` ${r.details}`));
|
|
226
|
+
}
|
|
227
|
+
if (!r.ok)
|
|
228
|
+
allOk = false;
|
|
229
|
+
}
|
|
230
|
+
console.log();
|
|
231
|
+
if (allOk) {
|
|
232
|
+
console.log(chalk.green.bold('All checks passed!'));
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
console.log(chalk.yellow('Some checks failed. Fix the issues above and try again.'));
|
|
236
|
+
process.exit(1);
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
|