@optiqcode/cli 1.4.0 ā 1.6.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/dist/commands/auth.js +1 -1
- package/dist/commands/index.js +1 -1
- package/dist/commands/watch.js +1 -1
- package/dist/index.js +187 -89
- package/package.json +1 -1
package/dist/commands/auth.js
CHANGED
|
@@ -3,7 +3,7 @@ import axios from 'axios';
|
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import ora from 'ora';
|
|
5
5
|
import { getConfig, saveConfig, clearConfig } from '../utils/config.js';
|
|
6
|
-
const API_URL = process.env.OPTIQ_BACKEND_URL ? `${process.env.OPTIQ_BACKEND_URL}/api` : '
|
|
6
|
+
const API_URL = process.env.OPTIQ_BACKEND_URL ? `${process.env.OPTIQ_BACKEND_URL}/api` : 'https://api.optiqcode.com/api';
|
|
7
7
|
export async function login() {
|
|
8
8
|
// Test comment: verifying incremental indexing works correctly
|
|
9
9
|
console.log(chalk.blue('š Login to Optiq\n'));
|
package/dist/commands/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import path from 'path';
|
|
|
6
6
|
import fs from 'fs/promises';
|
|
7
7
|
import { getConfig } from '../utils/config.js';
|
|
8
8
|
import { isValidDirectory, getGitIgnorePatterns, shouldIgnoreFile } from '../utils/files.js';
|
|
9
|
-
const API_URL = process.env.OPTIQ_BACKEND_URL ? `${process.env.OPTIQ_BACKEND_URL}/api` : '
|
|
9
|
+
const API_URL = process.env.OPTIQ_BACKEND_URL ? `${process.env.OPTIQ_BACKEND_URL}/api` : 'https://api.optiqcode.com/api';
|
|
10
10
|
export async function index(options) {
|
|
11
11
|
const config = await getConfig();
|
|
12
12
|
if (!config) {
|
package/dist/commands/watch.js
CHANGED
|
@@ -6,7 +6,7 @@ import path from 'path';
|
|
|
6
6
|
import fs from 'fs/promises';
|
|
7
7
|
import { getConfig } from '../utils/config.js';
|
|
8
8
|
import { isValidDirectory, getGitIgnorePatterns, shouldIgnoreFile } from '../utils/files.js';
|
|
9
|
-
const API_URL = process.env.OPTIQ_BACKEND_URL ? `${process.env.OPTIQ_BACKEND_URL}/api` : '
|
|
9
|
+
const API_URL = process.env.OPTIQ_BACKEND_URL ? `${process.env.OPTIQ_BACKEND_URL}/api` : 'https://api.optiqcode.com/api';
|
|
10
10
|
export async function watch(options) {
|
|
11
11
|
const config = await getConfig();
|
|
12
12
|
if (!config) {
|
package/dist/index.js
CHANGED
|
@@ -9,10 +9,10 @@ import fs from 'fs/promises';
|
|
|
9
9
|
import logUpdate from 'log-update';
|
|
10
10
|
import { getConfig, saveConfig } from './utils/config.js';
|
|
11
11
|
import { isValidDirectory, getGitIgnorePatterns, shouldIgnoreFile } from './utils/files.js';
|
|
12
|
-
const BACKEND_URL = process.env.OPTIQ_BACKEND_URL || '
|
|
12
|
+
const BACKEND_URL = process.env.OPTIQ_BACKEND_URL || 'https://api.optiqcode.com';
|
|
13
13
|
async function showBanner() {
|
|
14
14
|
console.clear();
|
|
15
|
-
console.log(chalk.
|
|
15
|
+
console.log(chalk.cyan.bold(`
|
|
16
16
|
___ _ _
|
|
17
17
|
/ _ \\ _ __ | |_(_) __ _
|
|
18
18
|
| | | | '_ \\| __| |/ _\` |
|
|
@@ -20,28 +20,49 @@ async function showBanner() {
|
|
|
20
20
|
\\___/| .__/ \\__|_|\\__, |
|
|
21
21
|
|_| |_|
|
|
22
22
|
`));
|
|
23
|
-
console.log(chalk.gray('
|
|
23
|
+
console.log(chalk.gray(' AI-powered code indexing & search'));
|
|
24
|
+
console.log(chalk.gray(' v1.6.0\n'));
|
|
25
|
+
}
|
|
26
|
+
function showHelp() {
|
|
27
|
+
console.log(chalk.cyan.bold('Optiq CLI') + chalk.gray(' - AI-powered code indexing\n'));
|
|
28
|
+
console.log(chalk.white('Usage:'));
|
|
29
|
+
console.log(chalk.gray(' optiq [command] [options]\n'));
|
|
30
|
+
console.log(chalk.white('Commands:'));
|
|
31
|
+
console.log(chalk.gray(' login Login with email & OTP'));
|
|
32
|
+
console.log(chalk.gray(' index Index current directory once'));
|
|
33
|
+
console.log(chalk.gray(' watch Watch directory and auto-index changes'));
|
|
34
|
+
console.log(chalk.gray(' logout Clear stored credentials'));
|
|
35
|
+
console.log(chalk.gray(' key Show your API key'));
|
|
36
|
+
console.log(chalk.gray(' help Show this help message\n'));
|
|
37
|
+
console.log(chalk.white('Options:'));
|
|
38
|
+
console.log(chalk.gray(' --path <dir> Specify directory to index (default: current)\n'));
|
|
39
|
+
console.log(chalk.white('Examples:'));
|
|
40
|
+
console.log(chalk.gray(' optiq login'));
|
|
41
|
+
console.log(chalk.gray(' optiq index'));
|
|
42
|
+
console.log(chalk.gray(' optiq watch'));
|
|
43
|
+
console.log(chalk.gray(' optiq index --path /path/to/project\n'));
|
|
44
|
+
console.log(chalk.gray('Get started: https://github.com/optiqcode/optiq'));
|
|
24
45
|
}
|
|
25
46
|
async function login() {
|
|
26
|
-
console.log(chalk.
|
|
47
|
+
console.log(chalk.cyan('š Login\n'));
|
|
27
48
|
const { email } = await prompts({
|
|
28
49
|
type: 'text',
|
|
29
50
|
name: 'email',
|
|
30
51
|
message: 'Email:',
|
|
31
|
-
validate: (value) => value.includes('@') || '
|
|
52
|
+
validate: (value) => value.includes('@') || 'Invalid email',
|
|
32
53
|
});
|
|
33
54
|
if (!email) {
|
|
34
|
-
console.log(chalk.gray('\
|
|
55
|
+
console.log(chalk.gray('\nCancelled'));
|
|
35
56
|
process.exit(0);
|
|
36
57
|
}
|
|
37
|
-
const spinner = ora({ text: 'Sending code...', color: '
|
|
58
|
+
const spinner = ora({ text: 'Sending code...', color: 'cyan' }).start();
|
|
38
59
|
try {
|
|
39
60
|
// Send OTP
|
|
40
61
|
const otpResponse = await axios.post(`${BACKEND_URL}/api/auth/send-otp`, { email }, { timeout: 10000 });
|
|
41
62
|
if (!otpResponse.data.success) {
|
|
42
63
|
throw new Error('Failed to send code');
|
|
43
64
|
}
|
|
44
|
-
spinner.succeed(chalk.
|
|
65
|
+
spinner.succeed(chalk.cyan('ā Code sent\n'));
|
|
45
66
|
const { code } = await prompts({
|
|
46
67
|
type: 'text',
|
|
47
68
|
name: 'code',
|
|
@@ -52,10 +73,10 @@ async function login() {
|
|
|
52
73
|
},
|
|
53
74
|
});
|
|
54
75
|
if (!code) {
|
|
55
|
-
console.log(chalk.gray('\
|
|
76
|
+
console.log(chalk.gray('\nCancelled'));
|
|
56
77
|
return false;
|
|
57
78
|
}
|
|
58
|
-
const verifySpinner = ora({ text: 'Verifying...', color: '
|
|
79
|
+
const verifySpinner = ora({ text: 'Verifying...', color: 'cyan' }).start();
|
|
59
80
|
// Verify OTP
|
|
60
81
|
const verifyResponse = await axios.post(`${BACKEND_URL}/api/auth/verify-otp`, { email, code }, { timeout: 10000 });
|
|
61
82
|
if (verifyResponse.data.success) {
|
|
@@ -82,29 +103,95 @@ async function login() {
|
|
|
82
103
|
token: token,
|
|
83
104
|
apiKey: validateResponse.data.context_engine_api_key || '',
|
|
84
105
|
});
|
|
85
|
-
verifySpinner.succeed(chalk.
|
|
106
|
+
verifySpinner.succeed(chalk.cyan(`ā Logged in as ${email}\n`));
|
|
86
107
|
return true;
|
|
87
108
|
}
|
|
88
109
|
else {
|
|
89
|
-
verifySpinner.fail(chalk.
|
|
110
|
+
verifySpinner.fail(chalk.red('ā Invalid code'));
|
|
90
111
|
return false;
|
|
91
112
|
}
|
|
92
113
|
}
|
|
93
114
|
catch (error) {
|
|
94
|
-
spinner.fail(chalk.
|
|
115
|
+
spinner.fail(chalk.red('ā Login failed'));
|
|
95
116
|
if (error.response?.data?.error) {
|
|
96
|
-
console.log(chalk.gray(error.response.data.error));
|
|
117
|
+
console.log(chalk.gray(' ' + error.response.data.error));
|
|
97
118
|
}
|
|
98
119
|
else {
|
|
99
|
-
console.log(chalk.gray(error.message));
|
|
120
|
+
console.log(chalk.gray(' ' + error.message));
|
|
100
121
|
}
|
|
101
122
|
return false;
|
|
102
123
|
}
|
|
103
124
|
}
|
|
104
125
|
async function main() {
|
|
105
|
-
|
|
106
|
-
|
|
126
|
+
const args = process.argv.slice(2);
|
|
127
|
+
const command = args[0];
|
|
128
|
+
// Parse --path option
|
|
129
|
+
const pathIndex = args.indexOf('--path');
|
|
130
|
+
const targetPath = pathIndex >= 0 && args[pathIndex + 1]
|
|
131
|
+
? path.resolve(args[pathIndex + 1])
|
|
132
|
+
: path.resolve(process.cwd());
|
|
133
|
+
// Handle commands
|
|
134
|
+
if (command === 'help' || command === '--help' || command === '-h') {
|
|
135
|
+
showHelp();
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
if (command === 'login') {
|
|
139
|
+
await showBanner();
|
|
140
|
+
const success = await login();
|
|
141
|
+
process.exit(success ? 0 : 1);
|
|
142
|
+
}
|
|
143
|
+
if (command === 'logout') {
|
|
144
|
+
const { clearConfig } = await import('./utils/config.js');
|
|
145
|
+
await clearConfig();
|
|
146
|
+
console.log(chalk.cyan('ā Logged out successfully'));
|
|
147
|
+
process.exit(0);
|
|
148
|
+
}
|
|
149
|
+
if (command === 'key') {
|
|
150
|
+
const config = await getConfig();
|
|
151
|
+
if (!config) {
|
|
152
|
+
console.log(chalk.red('ā Not logged in'));
|
|
153
|
+
console.log(chalk.gray('Run: optiq login'));
|
|
154
|
+
process.exit(1);
|
|
155
|
+
}
|
|
156
|
+
console.log(chalk.cyan('\nš Your API Key:\n'));
|
|
157
|
+
console.log(chalk.white(config.apiKey || 'No API key found'));
|
|
158
|
+
console.log(chalk.gray('\nUse this for the MCP server or direct API calls'));
|
|
159
|
+
console.log(chalk.gray('Keep this secret!\n'));
|
|
160
|
+
process.exit(0);
|
|
161
|
+
}
|
|
162
|
+
// Check authentication for index/watch commands
|
|
107
163
|
let config = await getConfig();
|
|
164
|
+
if (command === 'index' || command === 'watch') {
|
|
165
|
+
if (!config) {
|
|
166
|
+
console.log(chalk.red('ā Not logged in'));
|
|
167
|
+
console.log(chalk.gray('Run: optiq login'));
|
|
168
|
+
process.exit(1);
|
|
169
|
+
}
|
|
170
|
+
// Safety check
|
|
171
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE;
|
|
172
|
+
if (homeDir && path.resolve(targetPath) === path.resolve(homeDir)) {
|
|
173
|
+
console.log(chalk.red('ā Cannot index home directory'));
|
|
174
|
+
console.log(chalk.gray('Specify a project directory'));
|
|
175
|
+
process.exit(1);
|
|
176
|
+
}
|
|
177
|
+
// Validate directory
|
|
178
|
+
const validation = await isValidDirectory(targetPath);
|
|
179
|
+
if (!validation.valid) {
|
|
180
|
+
console.log(chalk.red(`ā ${validation.error}`));
|
|
181
|
+
process.exit(1);
|
|
182
|
+
}
|
|
183
|
+
console.log(chalk.cyan('š ' + path.basename(targetPath)));
|
|
184
|
+
console.log(chalk.gray(` ${validation.fileCount} files ⢠${targetPath}\n`));
|
|
185
|
+
if (command === 'index') {
|
|
186
|
+
await indexOnce(targetPath, config);
|
|
187
|
+
}
|
|
188
|
+
else {
|
|
189
|
+
await watchDirectory(targetPath, config);
|
|
190
|
+
}
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
// Interactive mode if no command
|
|
194
|
+
await showBanner();
|
|
108
195
|
if (!config) {
|
|
109
196
|
const success = await login();
|
|
110
197
|
if (!success) {
|
|
@@ -116,54 +203,49 @@ async function main() {
|
|
|
116
203
|
}
|
|
117
204
|
}
|
|
118
205
|
else {
|
|
119
|
-
console.log(chalk.
|
|
206
|
+
console.log(chalk.cyan('ā ' + config.email));
|
|
120
207
|
console.log();
|
|
121
208
|
}
|
|
122
|
-
|
|
123
|
-
// Safety check: prevent indexing home directory
|
|
209
|
+
// Safety check
|
|
124
210
|
const homeDir = process.env.HOME || process.env.USERPROFILE;
|
|
125
211
|
if (homeDir && path.resolve(targetPath) === path.resolve(homeDir)) {
|
|
126
|
-
console.log(chalk.
|
|
127
|
-
console.log(chalk.gray('Please run this from a project directory'));
|
|
212
|
+
console.log(chalk.red('ā Cannot index home directory'));
|
|
128
213
|
process.exit(1);
|
|
129
214
|
}
|
|
130
215
|
// Validate directory
|
|
131
216
|
const validation = await isValidDirectory(targetPath);
|
|
132
217
|
if (!validation.valid) {
|
|
133
|
-
console.log(chalk.
|
|
218
|
+
console.log(chalk.red(`ā ${validation.error}`));
|
|
134
219
|
process.exit(1);
|
|
135
220
|
}
|
|
136
|
-
console.log(chalk.
|
|
137
|
-
console.log(chalk.gray(` ${validation.fileCount} files
|
|
138
|
-
console.log(chalk.gray(` ${targetPath}\n`));
|
|
221
|
+
console.log(chalk.cyan('š ' + path.basename(targetPath)));
|
|
222
|
+
console.log(chalk.gray(` ${validation.fileCount} files ⢠${targetPath}\n`));
|
|
139
223
|
// Ask what to do
|
|
140
224
|
const { action } = await prompts({
|
|
141
225
|
type: 'select',
|
|
142
226
|
name: 'action',
|
|
143
|
-
message: '
|
|
227
|
+
message: 'Choose action:',
|
|
144
228
|
choices: [
|
|
145
|
-
{ title: 'š Watch and auto-index changes', value: 'watch' },
|
|
146
229
|
{ title: 'š¦ Index once', value: 'index' },
|
|
147
|
-
{ title: '
|
|
230
|
+
{ title: 'š Watch & auto-index', value: 'watch' },
|
|
231
|
+
{ title: 'š Show API Key', value: 'key' },
|
|
148
232
|
{ title: 'šŖ Logout', value: 'logout' },
|
|
149
|
-
{ title: 'ā Exit', value: 'exit' },
|
|
150
233
|
],
|
|
151
234
|
});
|
|
152
|
-
if (action
|
|
153
|
-
console.log(chalk.gray('\
|
|
235
|
+
if (!action) {
|
|
236
|
+
console.log(chalk.gray('\nCancelled'));
|
|
154
237
|
process.exit(0);
|
|
155
238
|
}
|
|
156
|
-
if (action === '
|
|
157
|
-
console.log(chalk.
|
|
158
|
-
console.log(chalk.white
|
|
159
|
-
console.log(chalk.gray('\
|
|
160
|
-
console.log(chalk.gray('Keep this key secret and never share it publicly.\n'));
|
|
239
|
+
if (action === 'key') {
|
|
240
|
+
console.log(chalk.cyan('\nš Your API Key:\n'));
|
|
241
|
+
console.log(chalk.white(config.apiKey));
|
|
242
|
+
console.log(chalk.gray('\nKeep this secret!\n'));
|
|
161
243
|
process.exit(0);
|
|
162
244
|
}
|
|
163
245
|
if (action === 'logout') {
|
|
164
246
|
const { clearConfig } = await import('./utils/config.js');
|
|
165
247
|
await clearConfig();
|
|
166
|
-
console.log(chalk.
|
|
248
|
+
console.log(chalk.cyan('\nā Logged out'));
|
|
167
249
|
process.exit(0);
|
|
168
250
|
}
|
|
169
251
|
if (action === 'index') {
|
|
@@ -174,53 +256,72 @@ async function main() {
|
|
|
174
256
|
}
|
|
175
257
|
}
|
|
176
258
|
async function indexOnce(targetPath, config) {
|
|
177
|
-
const spinner = ora({ text: 'Collecting files...', color: '
|
|
259
|
+
const spinner = ora({ text: 'Collecting files...', color: 'cyan' }).start();
|
|
178
260
|
try {
|
|
179
261
|
const files = await collectFiles(targetPath);
|
|
180
262
|
spinner.text = `Reading ${files.length} files...`;
|
|
181
263
|
const fileContents = {};
|
|
264
|
+
let processed = 0;
|
|
182
265
|
for (const file of files) {
|
|
183
266
|
try {
|
|
184
267
|
const content = await fs.readFile(file, 'utf-8');
|
|
185
|
-
const relativePath = path.relative(targetPath, file);
|
|
268
|
+
const relativePath = path.relative(targetPath, file).replace(/\\/g, '/');
|
|
186
269
|
fileContents[relativePath] = content;
|
|
270
|
+
processed++;
|
|
271
|
+
if (processed % 50 === 0) {
|
|
272
|
+
spinner.text = `Reading files... ${processed}/${files.length}`;
|
|
273
|
+
}
|
|
187
274
|
}
|
|
188
275
|
catch (error) {
|
|
189
|
-
// Skip files
|
|
276
|
+
// Skip unreadable files
|
|
190
277
|
}
|
|
191
278
|
}
|
|
192
|
-
spinner.text = 'Uploading to Optiq...';
|
|
193
279
|
const filesArray = Object.entries(fileContents).map(([path, content]) => ({
|
|
194
280
|
path,
|
|
195
281
|
content,
|
|
196
282
|
}));
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
283
|
+
// Batch upload
|
|
284
|
+
const BATCH_SIZE = 50;
|
|
285
|
+
let totalFiles = 0;
|
|
286
|
+
let totalEntities = 0;
|
|
287
|
+
let repoId = '';
|
|
288
|
+
for (let i = 0; i < filesArray.length; i += BATCH_SIZE) {
|
|
289
|
+
const batch = filesArray.slice(i, i + BATCH_SIZE);
|
|
290
|
+
const batchNum = Math.floor(i / BATCH_SIZE) + 1;
|
|
291
|
+
const totalBatches = Math.ceil(filesArray.length / BATCH_SIZE);
|
|
292
|
+
spinner.text = `Uploading... batch ${batchNum}/${totalBatches}`;
|
|
293
|
+
const response = await axios.post(`${BACKEND_URL}/api/nexus/index/content`, {
|
|
294
|
+
repository_path: targetPath,
|
|
295
|
+
files: batch,
|
|
296
|
+
}, {
|
|
297
|
+
headers: {
|
|
298
|
+
'X-API-Key': config.apiKey,
|
|
299
|
+
'Content-Type': 'application/json',
|
|
300
|
+
},
|
|
301
|
+
timeout: 0,
|
|
302
|
+
});
|
|
303
|
+
if (!response.data.success) {
|
|
304
|
+
spinner.fail(chalk.red('ā Indexing failed'));
|
|
305
|
+
console.log(chalk.gray(response.data.error || 'Unknown error'));
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
repoId = response.data.repo_id;
|
|
309
|
+
totalFiles += response.data.stats?.files_indexed || 0;
|
|
310
|
+
totalEntities += response.data.stats?.entities_indexed || 0;
|
|
215
311
|
}
|
|
312
|
+
spinner.succeed(chalk.cyan('ā Indexed'));
|
|
313
|
+
console.log(chalk.gray(` ${totalFiles} files ⢠${totalEntities} entities`));
|
|
314
|
+
console.log(chalk.cyan('\nš Repository ID:'));
|
|
315
|
+
console.log(chalk.white(` ${repoId}`));
|
|
316
|
+
console.log(chalk.gray('\n Use this ID with the MCP server\n'));
|
|
216
317
|
}
|
|
217
318
|
catch (error) {
|
|
218
|
-
spinner.fail(chalk.
|
|
319
|
+
spinner.fail(chalk.red('ā Failed'));
|
|
219
320
|
if (error.response?.data?.error) {
|
|
220
|
-
console.log(chalk.gray(error.response.data.error));
|
|
321
|
+
console.log(chalk.gray(' ' + error.response.data.error));
|
|
221
322
|
}
|
|
222
323
|
else {
|
|
223
|
-
console.log(chalk.gray(error.message));
|
|
324
|
+
console.log(chalk.gray(' ' + error.message));
|
|
224
325
|
}
|
|
225
326
|
}
|
|
226
327
|
}
|
|
@@ -238,9 +339,8 @@ async function watchDirectory(targetPath, config) {
|
|
|
238
339
|
const existingRepo = repoListResponse.data.repositories.find((r) => r.path === targetPath);
|
|
239
340
|
if (existingRepo) {
|
|
240
341
|
repoId = existingRepo.id;
|
|
241
|
-
console.log(chalk.
|
|
242
|
-
console.log(chalk.
|
|
243
|
-
console.log();
|
|
342
|
+
console.log(chalk.cyan('ā Already indexed'));
|
|
343
|
+
console.log(chalk.gray(` Repo ID: ${repoId}\n`));
|
|
244
344
|
}
|
|
245
345
|
}
|
|
246
346
|
}
|
|
@@ -300,22 +400,22 @@ async function watchDirectory(targetPath, config) {
|
|
|
300
400
|
repoId = response.data.repo_id;
|
|
301
401
|
uploadedCount += batch.length;
|
|
302
402
|
}
|
|
303
|
-
spinner.succeed(chalk.
|
|
304
|
-
console.log(chalk.gray(
|
|
305
|
-
console.log();
|
|
403
|
+
spinner.succeed(chalk.cyan(`ā Indexed ${files.length} files`));
|
|
404
|
+
console.log(chalk.gray(` Repo ID: ${repoId}\n`));
|
|
306
405
|
}
|
|
307
406
|
catch (error) {
|
|
308
|
-
spinner.fail(chalk.
|
|
407
|
+
spinner.fail(chalk.red('ā Failed'));
|
|
309
408
|
if (error.response?.data?.error) {
|
|
310
|
-
console.log(chalk.gray(error.response.data.error));
|
|
409
|
+
console.log(chalk.gray(' ' + error.response.data.error));
|
|
311
410
|
}
|
|
312
411
|
else {
|
|
313
|
-
console.log(chalk.gray(error.message));
|
|
412
|
+
console.log(chalk.gray(' ' + error.message));
|
|
314
413
|
}
|
|
315
414
|
return;
|
|
316
415
|
}
|
|
317
416
|
}
|
|
318
|
-
console.log(chalk.
|
|
417
|
+
console.log(chalk.cyan('š Watching for changes...'));
|
|
418
|
+
console.log(chalk.gray(' Press Ctrl+C to stop\n'));
|
|
319
419
|
const ignorePatterns = await getGitIgnorePatterns(targetPath);
|
|
320
420
|
const watcher = chokidar.watch(targetPath, {
|
|
321
421
|
ignored: (filePath) => {
|
|
@@ -352,17 +452,14 @@ async function watchDirectory(targetPath, config) {
|
|
|
352
452
|
const uptime = formatUptime(Date.now() - sessionStartTime);
|
|
353
453
|
const timeSinceLastIndex = Math.floor((Date.now() - lastIndexedTime) / 1000);
|
|
354
454
|
const lines = [];
|
|
355
|
-
lines.push(chalk.
|
|
356
|
-
lines.push(`${chalk.cyan('
|
|
357
|
-
lines.push(
|
|
358
|
-
lines.push(` ${chalk.gray('Total Indexed:')} ${chalk.white(totalIndexed)} ${chalk.gray('changes')}`);
|
|
359
|
-
lines.push(` ${chalk.gray('Unique Files:')} ${chalk.white(allIndexedFiles.size)}`);
|
|
360
|
-
lines.push('');
|
|
361
|
-
lines.push(`${chalk.green('ā')} ${chalk.gray('Last Activity:')} ${chalk.white(lastIndexedFile || 'None')}`);
|
|
455
|
+
lines.push(chalk.gray('ā'.repeat(50)));
|
|
456
|
+
lines.push(`${chalk.cyan('š Watching')} ${chalk.gray('ā¢')} ${chalk.white(uptime)} ${chalk.gray('uptime')}`);
|
|
457
|
+
lines.push(`${chalk.gray(' Indexed:')} ${chalk.white(totalIndexed)} ${chalk.gray('changes')} ${chalk.gray('ā¢')} ${chalk.white(allIndexedFiles.size)} ${chalk.gray('files')}`);
|
|
362
458
|
if (lastIndexedFile) {
|
|
363
|
-
|
|
459
|
+
const timeStr = timeSinceLastIndex < 60 ? `${timeSinceLastIndex}s` : `${Math.floor(timeSinceLastIndex / 60)}m`;
|
|
460
|
+
lines.push(`${chalk.gray(' Last:')} ${chalk.white(lastIndexedFile)} ${chalk.gray(`(${timeStr} ago)`)}`);
|
|
364
461
|
}
|
|
365
|
-
lines.push(chalk.
|
|
462
|
+
lines.push(chalk.gray('ā'.repeat(50)));
|
|
366
463
|
lines.push('');
|
|
367
464
|
logUpdate(lines.join('\n'));
|
|
368
465
|
};
|
|
@@ -436,14 +533,14 @@ async function watchDirectory(targetPath, config) {
|
|
|
436
533
|
}
|
|
437
534
|
else {
|
|
438
535
|
logUpdate.clear();
|
|
439
|
-
console.log(chalk.
|
|
440
|
-
console.log(chalk.gray(response.data.error));
|
|
536
|
+
console.log(chalk.red(`ā Failed to index`));
|
|
537
|
+
console.log(chalk.gray(` ${response.data.error}`));
|
|
441
538
|
}
|
|
442
539
|
}
|
|
443
540
|
catch (error) {
|
|
444
541
|
logUpdate.clear();
|
|
445
|
-
console.log(chalk.
|
|
446
|
-
console.log(chalk.gray(error.response?.data || error.message));
|
|
542
|
+
console.log(chalk.red(`ā Failed to index`));
|
|
543
|
+
console.log(chalk.gray(` ${error.response?.data?.error || error.message}`));
|
|
447
544
|
}
|
|
448
545
|
isProcessing = false;
|
|
449
546
|
// Check if there are more pending changes and process them
|
|
@@ -471,11 +568,12 @@ async function watchDirectory(targetPath, config) {
|
|
|
471
568
|
scheduleProcess();
|
|
472
569
|
})
|
|
473
570
|
.on('error', (error) => {
|
|
474
|
-
|
|
571
|
+
logUpdate.clear();
|
|
572
|
+
console.log(chalk.red('ā Watcher error:'), chalk.gray(error.message));
|
|
475
573
|
});
|
|
476
|
-
console.log(chalk.gray('Press Ctrl+C to stop\n'));
|
|
477
574
|
process.on('SIGINT', () => {
|
|
478
|
-
|
|
575
|
+
logUpdate.clear();
|
|
576
|
+
console.log(chalk.cyan('\nā Stopped watching'));
|
|
479
577
|
watcher.close();
|
|
480
578
|
process.exit(0);
|
|
481
579
|
});
|