canvaslms-cli 1.6.2 → 1.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/CHANGELOG.md +221 -195
  2. package/README.md +131 -129
  3. package/dist/commands/announcements.d.ts +2 -2
  4. package/dist/commands/announcements.d.ts.map +1 -1
  5. package/dist/commands/announcements.js +29 -20
  6. package/dist/commands/announcements.js.map +1 -1
  7. package/dist/commands/api.d.ts +1 -1
  8. package/dist/commands/api.d.ts.map +1 -1
  9. package/dist/commands/api.js +1 -1
  10. package/dist/commands/api.js.map +1 -1
  11. package/dist/commands/assignments.d.ts +2 -2
  12. package/dist/commands/assignments.d.ts.map +1 -1
  13. package/dist/commands/assignments.js +24 -19
  14. package/dist/commands/assignments.js.map +1 -1
  15. package/dist/commands/config.d.ts.map +1 -1
  16. package/dist/commands/config.js +102 -85
  17. package/dist/commands/config.js.map +1 -1
  18. package/dist/commands/grades.d.ts +2 -2
  19. package/dist/commands/grades.d.ts.map +1 -1
  20. package/dist/commands/grades.js +183 -228
  21. package/dist/commands/grades.js.map +1 -1
  22. package/dist/commands/list.d.ts +1 -1
  23. package/dist/commands/list.d.ts.map +1 -1
  24. package/dist/commands/list.js +22 -20
  25. package/dist/commands/list.js.map +1 -1
  26. package/dist/commands/profile.d.ts.map +1 -1
  27. package/dist/commands/profile.js +57 -32
  28. package/dist/commands/profile.js.map +1 -1
  29. package/dist/commands/submit.d.ts +1 -2
  30. package/dist/commands/submit.d.ts.map +1 -1
  31. package/dist/commands/submit.js +88 -79
  32. package/dist/commands/submit.js.map +1 -1
  33. package/dist/index.d.ts +14 -14
  34. package/dist/index.js +14 -14
  35. package/dist/lib/api-client.d.ts +3 -0
  36. package/dist/lib/api-client.d.ts.map +1 -1
  37. package/dist/lib/api-client.js +31 -16
  38. package/dist/lib/api-client.js.map +1 -1
  39. package/dist/lib/config-validator.d.ts.map +1 -1
  40. package/dist/lib/config-validator.js +12 -12
  41. package/dist/lib/config-validator.js.map +1 -1
  42. package/dist/lib/config.d.ts +1 -1
  43. package/dist/lib/config.d.ts.map +1 -1
  44. package/dist/lib/config.js +16 -14
  45. package/dist/lib/config.js.map +1 -1
  46. package/dist/lib/display.d.ts +11 -5
  47. package/dist/lib/display.d.ts.map +1 -1
  48. package/dist/lib/display.js +261 -169
  49. package/dist/lib/display.js.map +1 -1
  50. package/dist/lib/file-upload.d.ts.map +1 -1
  51. package/dist/lib/file-upload.js +17 -17
  52. package/dist/lib/file-upload.js.map +1 -1
  53. package/dist/lib/interactive.d.ts +1 -1
  54. package/dist/lib/interactive.d.ts.map +1 -1
  55. package/dist/lib/interactive.js +194 -144
  56. package/dist/lib/interactive.js.map +1 -1
  57. package/dist/src/index.d.ts +0 -1
  58. package/dist/src/index.js +62 -63
  59. package/dist/src/index.js.map +1 -1
  60. package/dist/types/index.d.ts +1 -1
  61. package/package.json +10 -3
  62. package/dist/commands/coursenames.d.ts +0 -15
  63. package/dist/commands/coursenames.d.ts.map +0 -1
  64. package/dist/commands/coursenames.js +0 -150
  65. package/dist/commands/coursenames.js.map +0 -1
  66. package/dist/lib/course-utils.d.ts +0 -6
  67. package/dist/lib/course-utils.d.ts.map +0 -1
  68. package/dist/lib/course-utils.js +0 -17
  69. package/dist/lib/course-utils.js.map +0 -1
@@ -1,22 +1,22 @@
1
- import readline from 'readline';
2
- import fs from 'fs';
3
- import path from 'path';
4
- import AdmZip from 'adm-zip';
5
- import chalk from 'chalk';
1
+ import readline from "readline";
2
+ import fs from "fs";
3
+ import path from "path";
4
+ import AdmZip from "adm-zip";
5
+ import chalk from "chalk";
6
6
  const KEYS = {
7
- UP: '\u001b[A',
8
- DOWN: '\u001b[B',
9
- LEFT: '\u001b[D',
10
- RIGHT: '\u001b[C',
11
- SPACE: ' ',
12
- ENTER: '\r',
13
- ESCAPE: '\u001b',
14
- BACKSPACE: '\u007f',
15
- TAB: '\t',
16
- CTRL_C: '\u0003'
7
+ UP: "\u001b[A",
8
+ DOWN: "\u001b[B",
9
+ LEFT: "\u001b[D",
10
+ RIGHT: "\u001b[C",
11
+ SPACE: " ",
12
+ ENTER: "\r",
13
+ ESCAPE: "\u001b",
14
+ BACKSPACE: "\u007f",
15
+ TAB: "\t",
16
+ CTRL_C: "\u0003",
17
17
  };
18
18
  export function createReadlineInterface() {
19
- if (process.stdin.isTTY && typeof process.stdin.setRawMode === 'function') {
19
+ if (process.stdin.isTTY && typeof process.stdin.setRawMode === "function") {
20
20
  try {
21
21
  process.stdin.setRawMode(false);
22
22
  }
@@ -26,7 +26,7 @@ export function createReadlineInterface() {
26
26
  return readline.createInterface({
27
27
  input: process.stdin,
28
28
  output: process.stdout,
29
- terminal: true
29
+ terminal: true,
30
30
  });
31
31
  }
32
32
  export function askQuestion(rl, question) {
@@ -46,7 +46,7 @@ export function askQuestionWithValidation(rl, question, validator, errorMessage)
46
46
  return;
47
47
  }
48
48
  else {
49
- console.log(errorMessage || 'Invalid input. Please try again.');
49
+ console.log(errorMessage || "Invalid input. Please try again.");
50
50
  }
51
51
  } while (true);
52
52
  });
@@ -78,22 +78,24 @@ export async function askConfirmation(rl, question, defaultYes = true, options =
78
78
  }
79
79
  export async function selectFromList(rl, items, displayProperty = null, allowCancel = true) {
80
80
  if (!items || items.length === 0) {
81
- console.log('No items to select from.');
81
+ console.log("No items to select from.");
82
82
  return null;
83
83
  }
84
- console.log('\nSelect an option:');
84
+ console.log("\nSelect an option:");
85
85
  items.forEach((item, index) => {
86
- const displayText = displayProperty && typeof item === 'object' && item !== null ? item[displayProperty] : item;
86
+ const displayText = displayProperty && typeof item === "object" && item !== null
87
+ ? item[displayProperty]
88
+ : item;
87
89
  console.log(`${index + 1}. ${displayText}`);
88
90
  });
89
91
  if (allowCancel) {
90
- console.log('0. Cancel');
92
+ console.log("0. Cancel");
91
93
  }
92
94
  const validator = (input) => {
93
95
  const num = parseInt(input);
94
96
  return !isNaN(num) && num >= (allowCancel ? 0 : 1) && num <= items.length;
95
97
  };
96
- const answer = await askQuestionWithValidation(rl, '\nEnter your choice: ', validator, `Please enter a number between ${allowCancel ? '0' : '1'} and ${items.length}.`);
98
+ const answer = await askQuestionWithValidation(rl, "\nEnter your choice: ", validator, `Please enter a number between ${allowCancel ? "0" : "1"} and ${items.length}.`);
97
99
  const choice = parseInt(answer);
98
100
  if (choice === 0 && allowCancel) {
99
101
  return null;
@@ -111,13 +113,14 @@ export function getSubfoldersRecursive(startDir = process.cwd()) {
111
113
  const stat = fs.statSync(fullPath);
112
114
  if (stat.isDirectory()) {
113
115
  const baseName = path.basename(fullPath);
114
- if (['node_modules', '.git', 'dist', 'build'].includes(baseName))
116
+ if (["node_modules", ".git", "dist", "build"].includes(baseName))
115
117
  continue;
116
118
  result.push(fullPath);
117
119
  walk(fullPath);
118
120
  }
119
121
  }
120
- catch (err) {
122
+ catch {
123
+ console.warn(`Skipped unreadable folder: ${fullPath}`);
121
124
  }
122
125
  }
123
126
  }
@@ -129,33 +132,34 @@ export function getFilesMatchingWildcard(pattern, currentDir = process.cwd()) {
129
132
  const allFolders = [currentDir, ...getSubfoldersRecursive(currentDir)];
130
133
  let allFiles = [];
131
134
  for (const folder of allFolders) {
132
- const files = fs.readdirSync(folder).map(f => path.join(folder, f));
135
+ const files = fs.readdirSync(folder).map((f) => path.join(folder, f));
133
136
  for (const filePath of files) {
134
137
  try {
135
138
  if (fs.statSync(filePath).isFile()) {
136
139
  allFiles.push(filePath);
137
140
  }
138
141
  }
139
- catch (e) { }
142
+ catch {
143
+ }
140
144
  }
141
145
  }
142
146
  let regexPattern;
143
147
  let matchFullPath = false;
144
- if (pattern === '*' || (!pattern.includes('.') && !pattern.includes('/'))) {
145
- regexPattern = new RegExp('.*', 'i');
148
+ if (pattern === "*" || (!pattern.includes(".") && !pattern.includes("/"))) {
149
+ regexPattern = new RegExp(".*", "i");
146
150
  matchFullPath = true;
147
151
  }
148
- else if (pattern.startsWith('*.')) {
152
+ else if (pattern.startsWith("*.")) {
149
153
  const extension = pattern.slice(2);
150
- regexPattern = new RegExp(`\\.${extension.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$`, 'i');
154
+ regexPattern = new RegExp(`\\.${extension.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`, "i");
151
155
  }
152
- else if (pattern.includes('*')) {
153
- regexPattern = new RegExp(pattern.replace(/\*/g, '.*').replace(/\?/g, '.'), 'i');
156
+ else if (pattern.includes("*")) {
157
+ regexPattern = new RegExp(pattern.replace(/\*/g, ".*").replace(/\?/g, "."), "i");
154
158
  }
155
159
  else {
156
- regexPattern = new RegExp(`^${pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}$`, 'i');
160
+ regexPattern = new RegExp(`^${pattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`, "i");
157
161
  }
158
- const matchedFiles = allFiles.filter(filePath => {
162
+ const matchedFiles = allFiles.filter((filePath) => {
159
163
  if (matchFullPath) {
160
164
  const relPath = path.relative(currentDir, filePath);
161
165
  return regexPattern.test(relPath);
@@ -173,40 +177,42 @@ export function getFilesMatchingWildcard(pattern, currentDir = process.cwd()) {
173
177
  }
174
178
  }
175
179
  export function pad(str, len) {
176
- return str + ' '.repeat(Math.max(0, len - str.length));
180
+ return str + " ".repeat(Math.max(0, len - str.length));
177
181
  }
178
182
  export async function selectFilesImproved(rl, currentDir = process.cwd()) {
179
183
  const selectedFiles = [];
180
- console.log(chalk.cyan.bold('\n' + '-'.repeat(50)));
181
- console.log(chalk.cyan.bold('File Selection'));
182
- console.log(chalk.cyan('-'.repeat(50)));
183
- console.log(chalk.yellow('Tips:'));
184
- console.log(' • Type filename to add individual files');
185
- console.log(' • Use wildcards: *.html, *.js, *.pdf, etc.');
184
+ console.log(chalk.cyan.bold("\n" + "-".repeat(50)));
185
+ console.log(chalk.cyan.bold("File Selection"));
186
+ console.log(chalk.cyan("-".repeat(50)));
187
+ console.log(chalk.yellow("Tips:"));
188
+ console.log(" • Type filename to add individual files");
189
+ console.log(" • Use wildcards: *.html, *.js, *.pdf, etc.");
186
190
  console.log(' • Type "browse" to see available files');
187
191
  console.log(' • Type "remove" to remove files from selection');
188
192
  console.log(' • Type ".." or "back" to return to previous menu');
189
- console.log(' • Press Enter with no input to finish selection\n');
193
+ console.log(" • Press Enter with no input to finish selection\n");
190
194
  while (true) {
191
195
  if (selectedFiles.length > 0) {
192
- console.log(chalk.cyan('\n' + '-'.repeat(50)));
196
+ console.log(chalk.cyan("\n" + "-".repeat(50)));
193
197
  console.log(chalk.cyan.bold(`Currently selected (${selectedFiles.length} files):`));
194
198
  selectedFiles.forEach((file, index) => {
195
199
  const stats = fs.statSync(file);
196
- const size = (stats.size / 1024).toFixed(1) + ' KB';
197
- console.log(pad(chalk.white((index + 1) + '.'), 5) + pad(path.basename(file), 35) + chalk.gray(size));
200
+ const size = (stats.size / 1024).toFixed(1) + " KB";
201
+ console.log(pad(chalk.white(index + 1 + "."), 5) +
202
+ pad(path.basename(file), 35) +
203
+ chalk.gray(size));
198
204
  });
199
- console.log(chalk.cyan('-'.repeat(50)));
205
+ console.log(chalk.cyan("-".repeat(50)));
200
206
  }
201
- const input = await askQuestion(rl, chalk.bold.cyan('\nAdd file (or press Enter to finish): '));
207
+ const input = await askQuestion(rl, chalk.bold.cyan("\nAdd file (or press Enter to finish): "));
202
208
  if (!input.trim())
203
209
  break;
204
- if (input === '..' || input.toLowerCase() === 'back') {
210
+ if (input === ".." || input.toLowerCase() === "back") {
205
211
  return selectedFiles;
206
212
  }
207
- if (input.toLowerCase() === 'browse') {
208
- console.log(chalk.cyan('\n' + '-'.repeat(50)));
209
- console.log(chalk.cyan.bold('Browsing available files:'));
213
+ if (input.toLowerCase() === "browse") {
214
+ console.log(chalk.cyan("\n" + "-".repeat(50)));
215
+ console.log(chalk.cyan.bold("Browsing available files:"));
210
216
  try {
211
217
  const listedFiles = [];
212
218
  function walk(dir) {
@@ -214,7 +220,7 @@ export async function selectFilesImproved(rl, currentDir = process.cwd()) {
214
220
  for (const entry of entries) {
215
221
  const fullPath = path.join(dir, entry);
216
222
  const relPath = path.relative(currentDir, fullPath);
217
- if (['node_modules', '.git', 'dist', 'build'].includes(entry))
223
+ if (["node_modules", ".git", "dist", "build"].includes(entry))
218
224
  continue;
219
225
  try {
220
226
  const stat = fs.statSync(fullPath);
@@ -222,41 +228,47 @@ export async function selectFilesImproved(rl, currentDir = process.cwd()) {
222
228
  walk(fullPath);
223
229
  }
224
230
  else if (stat.isFile()) {
225
- listedFiles.push({ path: fullPath, rel: relPath, size: stat.size });
231
+ listedFiles.push({
232
+ path: fullPath,
233
+ rel: relPath,
234
+ size: stat.size,
235
+ });
226
236
  }
227
237
  }
228
- catch (e) {
238
+ catch {
229
239
  continue;
230
240
  }
231
241
  }
232
242
  }
233
243
  walk(currentDir);
234
244
  if (listedFiles.length === 0) {
235
- console.log(chalk.red(' No suitable files found.'));
245
+ console.log(chalk.red(" No suitable files found."));
236
246
  }
237
247
  else {
238
248
  listedFiles.forEach((file, index) => {
239
249
  const sizeKB = (file.size / 1024).toFixed(1);
240
- console.log(pad(chalk.white((index + 1) + '.'), 5) + pad(file.rel, 35) + chalk.gray(sizeKB + ' KB'));
250
+ console.log(pad(chalk.white(index + 1 + "."), 5) +
251
+ pad(file.rel, 35) +
252
+ chalk.gray(sizeKB + " KB"));
241
253
  });
242
254
  }
243
255
  }
244
256
  catch (error) {
245
257
  const errorMessage = error instanceof Error ? error.message : String(error);
246
- console.log(chalk.red(' Error reading directory: ' + errorMessage));
258
+ console.log(chalk.red(" Error reading directory: " + errorMessage));
247
259
  }
248
260
  continue;
249
261
  }
250
- if (input.toLowerCase() === 'remove') {
262
+ if (input.toLowerCase() === "remove") {
251
263
  if (selectedFiles.length === 0) {
252
- console.log(chalk.red('No files selected to remove.'));
264
+ console.log(chalk.red("No files selected to remove."));
253
265
  continue;
254
266
  }
255
- console.log(chalk.cyan('\nSelect file to remove:'));
267
+ console.log(chalk.cyan("\nSelect file to remove:"));
256
268
  selectedFiles.forEach((file, index) => {
257
- console.log(pad(chalk.white((index + 1) + '.'), 5) + path.basename(file));
269
+ console.log(pad(chalk.white(index + 1 + "."), 5) + path.basename(file));
258
270
  });
259
- const removeChoice = await askQuestion(rl, chalk.bold.cyan('\nEnter number to remove (or press Enter to cancel): '));
271
+ const removeChoice = await askQuestion(rl, chalk.bold.cyan("\nEnter number to remove (or press Enter to cancel): "));
260
272
  if (removeChoice.trim()) {
261
273
  const removeIndex = parseInt(removeChoice) - 1;
262
274
  if (removeIndex >= 0 && removeIndex < selectedFiles.length) {
@@ -266,14 +278,14 @@ export async function selectFilesImproved(rl, currentDir = process.cwd()) {
266
278
  }
267
279
  }
268
280
  else {
269
- console.log(chalk.red('Invalid selection.'));
281
+ console.log(chalk.red("Invalid selection."));
270
282
  }
271
283
  }
272
284
  continue;
273
285
  }
274
286
  let filePath = input;
275
287
  let zipRequested = false;
276
- if (filePath.endsWith(' -zip')) {
288
+ if (filePath.endsWith(" -zip")) {
277
289
  filePath = filePath.slice(0, -5).trim();
278
290
  zipRequested = true;
279
291
  }
@@ -282,16 +294,16 @@ export async function selectFilesImproved(rl, currentDir = process.cwd()) {
282
294
  }
283
295
  try {
284
296
  if (!fs.existsSync(filePath)) {
285
- console.log(chalk.red('Error: File not found: ' + input));
297
+ console.log(chalk.red("Error: File not found: " + input));
286
298
  continue;
287
299
  }
288
300
  const stats = fs.statSync(filePath);
289
301
  if (zipRequested) {
290
302
  const baseName = path.basename(filePath);
291
- const zipName = baseName.replace(/\.[^/.]+$/, '') + '.zip';
303
+ const zipName = baseName.replace(/\.[^/.]+$/, "") + ".zip";
292
304
  const zipPath = path.join(currentDir, zipName);
293
305
  const zip = new AdmZip();
294
- process.stdout.write(chalk.yellow('Zipping, please wait... '));
306
+ process.stdout.write(chalk.yellow("Zipping, please wait... "));
295
307
  if (stats.isDirectory()) {
296
308
  zip.addLocalFolder(filePath);
297
309
  }
@@ -299,24 +311,24 @@ export async function selectFilesImproved(rl, currentDir = process.cwd()) {
299
311
  zip.addLocalFile(filePath);
300
312
  }
301
313
  else {
302
- console.log(chalk.red('Not a file or folder.'));
314
+ console.log(chalk.red("Not a file or folder."));
303
315
  continue;
304
316
  }
305
317
  zip.writeZip(zipPath);
306
- console.log(chalk.green('Done.'));
318
+ console.log(chalk.green("Done."));
307
319
  console.log(chalk.green(`Created ZIP: ${zipName}`));
308
320
  if (selectedFiles.includes(zipPath)) {
309
321
  console.log(chalk.yellow(`File already selected: ${zipName}`));
310
322
  continue;
311
323
  }
312
324
  selectedFiles.push(zipPath);
313
- const size = (fs.statSync(zipPath).size / 1024).toFixed(1) + ' KB';
325
+ const size = (fs.statSync(zipPath).size / 1024).toFixed(1) + " KB";
314
326
  console.log(chalk.green(`Added: ${zipName} (${size})`));
315
327
  continue;
316
328
  }
317
329
  if (stats.isDirectory()) {
318
330
  const baseName = path.basename(filePath);
319
- if (['node_modules', '.git', 'dist', 'build'].includes(baseName))
331
+ if (["node_modules", ".git", "dist", "build"].includes(baseName))
320
332
  continue;
321
333
  const collectedFiles = [];
322
334
  function walk(dir) {
@@ -326,7 +338,7 @@ export async function selectFilesImproved(rl, currentDir = process.cwd()) {
326
338
  const stat = fs.statSync(fullPath);
327
339
  if (stat.isDirectory()) {
328
340
  const baseName = path.basename(fullPath);
329
- if (['node_modules', '.git', 'dist', 'build'].includes(baseName))
341
+ if (["node_modules", ".git", "dist", "build"].includes(baseName))
330
342
  continue;
331
343
  walk(fullPath);
332
344
  }
@@ -346,13 +358,15 @@ export async function selectFilesImproved(rl, currentDir = process.cwd()) {
346
358
  const stat = fs.statSync(f);
347
359
  totalSize += stat.size;
348
360
  const relativePath = path.relative(currentDir, f);
349
- console.log(pad(chalk.white((i + 1) + '.'), 5) + pad(relativePath, 35) + chalk.gray((stat.size / 1024).toFixed(1) + ' KB'));
361
+ console.log(pad(chalk.white(i + 1 + "."), 5) +
362
+ pad(relativePath, 35) +
363
+ chalk.gray((stat.size / 1024).toFixed(1) + " KB"));
350
364
  });
351
- console.log(chalk.cyan('-'.repeat(50)));
365
+ console.log(chalk.cyan("-".repeat(50)));
352
366
  console.log(chalk.cyan(`Total size: ${(totalSize / 1024).toFixed(1)} KB`));
353
367
  const confirmFolder = await askConfirmation(rl, chalk.bold.cyan(`Add all ${collectedFiles.length} files from this folder?`), true);
354
368
  if (confirmFolder) {
355
- const newFiles = collectedFiles.filter(f => !selectedFiles.includes(f));
369
+ const newFiles = collectedFiles.filter((f) => !selectedFiles.includes(f));
356
370
  selectedFiles.push(...newFiles);
357
371
  console.log(chalk.green(`Added ${newFiles.length} new files (${collectedFiles.length - newFiles.length} already selected)`));
358
372
  }
@@ -363,12 +377,12 @@ export async function selectFilesImproved(rl, currentDir = process.cwd()) {
363
377
  continue;
364
378
  }
365
379
  selectedFiles.push(filePath);
366
- const size = (stats.size / 1024).toFixed(1) + ' KB';
380
+ const size = (stats.size / 1024).toFixed(1) + " KB";
367
381
  console.log(chalk.green(`Added: ${path.basename(filePath)} (${size})`));
368
382
  }
369
383
  catch (error) {
370
384
  const errorMessage = error instanceof Error ? error.message : String(error);
371
- console.log(chalk.red('Error accessing file: ' + errorMessage));
385
+ console.log(chalk.red("Error accessing file: " + errorMessage));
372
386
  }
373
387
  }
374
388
  return selectedFiles;
@@ -379,50 +393,79 @@ export async function selectFilesKeyboard(_rl, currentDir = process.cwd(), allow
379
393
  let currentPath = currentDir;
380
394
  let currentIndex = 0;
381
395
  let isNavigating = true;
382
- const prevDataListeners = process.stdin.listeners('data').slice();
383
- process.stdin.removeAllListeners('data');
396
+ const prevDataListeners = process.stdin.listeners("data").slice();
397
+ process.stdin.removeAllListeners("data");
384
398
  if (process.stdin.isTTY) {
385
399
  process.stdin.setRawMode(true);
386
400
  }
387
401
  process.stdin.resume();
388
- process.stdin.setEncoding('utf8');
402
+ process.stdin.setEncoding("utf8");
389
403
  function getFileIcon(filename) {
390
404
  const ext = path.extname(filename).toLowerCase();
391
405
  const icons = {
392
- '.pdf': '📄', '.doc': '📄', '.docx': '📄', '.txt': '📄',
393
- '.js': '📜', '.ts': '📜', '.py': '📜', '.java': '📜', '.cpp': '📜', '.c': '📜',
394
- '.html': '🌐', '.css': '🎨', '.scss': '🎨', '.less': '🎨',
395
- '.json': '⚙️', '.xml': '⚙️', '.yml': '⚙️', '.yaml': '⚙️',
396
- '.zip': '📦', '.rar': '📦', '.7z': '📦', '.tar': '📦',
397
- '.jpg': '🖼️', '.jpeg': '🖼️', '.png': '🖼️', '.gif': '🖼️', '.svg': '🖼️',
398
- '.mp4': '🎬', '.avi': '🎬', '.mov': '🎬', '.mkv': '🎬',
399
- '.mp3': '🎵', '.wav': '🎵', '.flac': '🎵'
406
+ ".pdf": "📄",
407
+ ".doc": "📄",
408
+ ".docx": "📄",
409
+ ".txt": "📄",
410
+ ".js": "📜",
411
+ ".ts": "📜",
412
+ ".py": "📜",
413
+ ".java": "📜",
414
+ ".cpp": "📜",
415
+ ".c": "📜",
416
+ ".html": "🌐",
417
+ ".css": "🎨",
418
+ ".scss": "🎨",
419
+ ".less": "🎨",
420
+ ".json": "⚙️",
421
+ ".xml": "⚙️",
422
+ ".yml": "⚙️",
423
+ ".yaml": "⚙️",
424
+ ".zip": "📦",
425
+ ".rar": "📦",
426
+ ".7z": "📦",
427
+ ".tar": "📦",
428
+ ".jpg": "🖼️",
429
+ ".jpeg": "🖼️",
430
+ ".png": "🖼️",
431
+ ".gif": "🖼️",
432
+ ".svg": "🖼️",
433
+ ".mp4": "🎬",
434
+ ".avi": "🎬",
435
+ ".mov": "🎬",
436
+ ".mkv": "🎬",
437
+ ".mp3": "🎵",
438
+ ".wav": "🎵",
439
+ ".flac": "🎵",
400
440
  };
401
- return icons[ext] || '📋';
441
+ return icons[ext] || "📋";
402
442
  }
403
443
  function buildBreadcrumb() {
404
444
  const relativePath = path.relative(currentDir, currentPath);
405
- if (!relativePath || relativePath === '.') {
406
- return '';
445
+ if (!relativePath || relativePath === ".") {
446
+ return "";
407
447
  }
408
448
  const parts = relativePath.split(path.sep);
409
- const breadcrumb = parts.map((part, index) => {
449
+ const breadcrumb = parts
450
+ .map((part, index) => {
410
451
  if (index === parts.length - 1) {
411
452
  return chalk.white.bold(part);
412
453
  }
413
454
  return chalk.gray(part);
414
- }).join(chalk.gray(' › '));
415
- return chalk.yellow('📂 ') + breadcrumb;
455
+ })
456
+ .join(chalk.gray(" › "));
457
+ return chalk.yellow("📂 ") + breadcrumb;
416
458
  }
417
459
  let lastDisplayLines = 0;
418
460
  function stripAnsi(str) {
419
- return str.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, '');
461
+ const ansiRegex = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g;
462
+ return str.replace(ansiRegex, "");
420
463
  }
421
- function printAndTrack(message = '') {
464
+ function printAndTrack(message = "") {
422
465
  console.log(message);
423
466
  const width = process.stdout.columns || 80;
424
467
  const clean = stripAnsi(message);
425
- const lines = clean.split('\n');
468
+ const lines = clean.split("\n");
426
469
  let count = 0;
427
470
  for (const line of lines) {
428
471
  count += Math.max(1, Math.ceil((line.length || 0.5) / width));
@@ -445,11 +488,11 @@ export async function selectFilesKeyboard(_rl, currentDir = process.cwd(), allow
445
488
  if (breadcrumb) {
446
489
  printAndTrack(breadcrumb);
447
490
  }
448
- printAndTrack(chalk.gray('💡 ↑↓←→:Navigate Space:Select Enter:Open/Finish Backspace:Up a:All c:Clear r:Reload Esc/Ctrl+C:Exit'));
491
+ printAndTrack(chalk.gray("💡 ↑↓←→:Navigate Space:Select Enter:Open/Finish Backspace:Up a:All c:Clear r:Reload Esc/Ctrl+C:Exit"));
449
492
  if (Array.isArray(allowedExtensions) && allowedExtensions.length > 0) {
450
493
  const exts = allowedExtensions
451
- .map(e => (e.startsWith('.') ? e.toLowerCase() : '.' + e.toLowerCase()))
452
- .join(', ');
494
+ .map((e) => e.startsWith(".") ? e.toLowerCase() : "." + e.toLowerCase())
495
+ .join(", ");
453
496
  printAndTrack(chalk.yellow(`Allowed: ${exts}`));
454
497
  }
455
498
  if (selectedFiles.length > 0) {
@@ -465,7 +508,7 @@ export async function selectFilesKeyboard(_rl, currentDir = process.cwd(), allow
465
508
  }
466
509
  printAndTrack();
467
510
  if (fileList.length === 0) {
468
- printAndTrack(chalk.yellow('📭 No files found in this directory.'));
511
+ printAndTrack(chalk.yellow("📭 No files found in this directory."));
469
512
  return;
470
513
  }
471
514
  displayFileTree();
@@ -479,36 +522,38 @@ export async function selectFilesKeyboard(_rl, currentDir = process.cwd(), allow
479
522
  if (startIdx > 0) {
480
523
  printAndTrack(chalk.gray(` ⋮ (${startIdx} items above)`));
481
524
  }
482
- const maxItemWidth = Math.max(...visibleItems.map(item => {
525
+ const maxItemWidth = Math.max(...visibleItems.map((item) => {
483
526
  const name = path.basename(item.path);
484
527
  return name.length + 4;
485
528
  }));
486
529
  const itemWidth = Math.min(Math.max(maxItemWidth, 15), 25);
487
530
  const columnsPerRow = Math.max(1, Math.floor((terminalWidth - 4) / itemWidth));
488
- let currentRow = '';
531
+ let currentRow = "";
489
532
  let itemsInCurrentRow = 0;
490
533
  visibleItems.forEach((item, index) => {
491
534
  const actualIndex = startIdx + index;
492
535
  const isSelected = selectedFiles.includes(item.path);
493
536
  const isCurrent = actualIndex === currentIndex;
494
- let icon = '';
495
- if (item.type === 'parent' || item.type === 'directory') {
496
- icon = '📁';
537
+ let icon = "";
538
+ if (item.type === "parent" || item.type === "directory") {
539
+ icon = "📁";
497
540
  }
498
541
  else {
499
542
  icon = getFileIcon(path.basename(item.path));
500
543
  }
501
544
  const name = item.name || path.basename(item.path);
502
- const truncatedName = name.length > itemWidth - 4 ? name.slice(0, itemWidth - 7) + '...' : name;
545
+ const truncatedName = name.length > itemWidth - 4
546
+ ? name.slice(0, itemWidth - 7) + "..."
547
+ : name;
503
548
  let itemDisplay = `${icon} ${truncatedName}`;
504
549
  if (isCurrent) {
505
550
  if (isSelected) {
506
551
  itemDisplay = chalk.black.bgGreen(` ${itemDisplay}`.padEnd(itemWidth - 1));
507
552
  }
508
- else if (item.type === 'parent') {
553
+ else if (item.type === "parent") {
509
554
  itemDisplay = chalk.white.bgBlue(` ${itemDisplay}`.padEnd(itemWidth - 1));
510
555
  }
511
- else if (item.type === 'directory') {
556
+ else if (item.type === "directory") {
512
557
  itemDisplay = chalk.black.bgCyan(` ${itemDisplay}`.padEnd(itemWidth - 1));
513
558
  }
514
559
  else {
@@ -519,10 +564,10 @@ export async function selectFilesKeyboard(_rl, currentDir = process.cwd(), allow
519
564
  if (isSelected) {
520
565
  itemDisplay = chalk.green(`✓${itemDisplay}`.padEnd(itemWidth));
521
566
  }
522
- else if (item.type === 'parent') {
567
+ else if (item.type === "parent") {
523
568
  itemDisplay = chalk.blue(` ${itemDisplay}`.padEnd(itemWidth));
524
569
  }
525
- else if (item.type === 'directory') {
570
+ else if (item.type === "directory") {
526
571
  itemDisplay = chalk.cyan(` ${itemDisplay}`.padEnd(itemWidth));
527
572
  }
528
573
  else {
@@ -531,9 +576,10 @@ export async function selectFilesKeyboard(_rl, currentDir = process.cwd(), allow
531
576
  }
532
577
  currentRow += itemDisplay;
533
578
  itemsInCurrentRow++;
534
- if (itemsInCurrentRow >= columnsPerRow || index === visibleItems.length - 1) {
579
+ if (itemsInCurrentRow >= columnsPerRow ||
580
+ index === visibleItems.length - 1) {
535
581
  printAndTrack(currentRow);
536
- currentRow = '';
582
+ currentRow = "";
537
583
  itemsInCurrentRow = 0;
538
584
  }
539
585
  });
@@ -555,39 +601,40 @@ export async function selectFilesKeyboard(_rl, currentDir = process.cwd(), allow
555
601
  try {
556
602
  if (currentPath !== currentDir) {
557
603
  fileList.push({
558
- type: 'parent',
604
+ type: "parent",
559
605
  path: path.dirname(currentPath),
560
- name: '..'
606
+ name: "..",
561
607
  });
562
608
  }
563
609
  const entries = fs.readdirSync(currentPath).sort();
564
- entries.forEach(entry => {
610
+ entries.forEach((entry) => {
565
611
  const fullPath = path.join(currentPath, entry);
566
612
  const stat = fs.statSync(fullPath);
567
613
  if (stat.isDirectory()) {
568
614
  fileList.push({
569
- type: 'directory',
615
+ type: "directory",
570
616
  path: fullPath,
571
- name: entry
617
+ name: entry,
572
618
  });
573
619
  }
574
620
  });
575
- entries.forEach(entry => {
621
+ entries.forEach((entry) => {
576
622
  const fullPath = path.join(currentPath, entry);
577
623
  const stat = fs.statSync(fullPath);
578
624
  if (stat.isFile()) {
579
- if (Array.isArray(allowedExtensions) && allowedExtensions.length > 0) {
580
- const lowerExts = allowedExtensions.map(e => (e.startsWith('.') ? e.toLowerCase() : '.' + e.toLowerCase()));
625
+ if (Array.isArray(allowedExtensions) &&
626
+ allowedExtensions.length > 0) {
627
+ const lowerExts = allowedExtensions.map((e) => e.startsWith(".") ? e.toLowerCase() : "." + e.toLowerCase());
581
628
  const ext = path.extname(entry).toLowerCase();
582
629
  if (!lowerExts.includes(ext)) {
583
630
  return;
584
631
  }
585
632
  }
586
633
  fileList.push({
587
- type: 'file',
634
+ type: "file",
588
635
  path: fullPath,
589
636
  name: entry,
590
- size: stat.size
637
+ size: stat.size,
591
638
  });
592
639
  }
593
640
  });
@@ -596,13 +643,13 @@ export async function selectFilesKeyboard(_rl, currentDir = process.cwd(), allow
596
643
  }
597
644
  }
598
645
  catch (error) {
599
- console.error('Error reading directory:', error);
646
+ console.error("Error reading directory:", error);
600
647
  fileList = [];
601
648
  }
602
649
  }
603
650
  function handleKeyInput(key) {
604
651
  const terminalWidth = process.stdout.columns || 80;
605
- const maxItemWidth = Math.max(...fileList.map(item => {
652
+ const maxItemWidth = Math.max(...fileList.map((item) => {
606
653
  const name = path.basename(item.path);
607
654
  return name.length + 4;
608
655
  }));
@@ -638,7 +685,7 @@ export async function selectFilesKeyboard(_rl, currentDir = process.cwd(), allow
638
685
  case KEYS.SPACE:
639
686
  if (fileList.length > 0) {
640
687
  const item = fileList[currentIndex];
641
- if (item && item.type === 'file') {
688
+ if (item && item.type === "file") {
642
689
  const index = selectedFiles.indexOf(item.path);
643
690
  if (index === -1) {
644
691
  selectedFiles.push(item.path);
@@ -653,7 +700,7 @@ export async function selectFilesKeyboard(_rl, currentDir = process.cwd(), allow
653
700
  case KEYS.ENTER:
654
701
  if (fileList.length > 0) {
655
702
  const item = fileList[currentIndex];
656
- if (item && (item.type === 'parent' || item.type === 'directory')) {
703
+ if (item && (item.type === "parent" || item.type === "directory")) {
657
704
  currentPath = item.path;
658
705
  currentIndex = 0;
659
706
  refreshFileList();
@@ -679,10 +726,10 @@ export async function selectFilesKeyboard(_rl, currentDir = process.cwd(), allow
679
726
  displayBrowser();
680
727
  }
681
728
  break;
682
- case 'a':
729
+ case "a":
683
730
  let addedCount = 0;
684
- fileList.forEach(item => {
685
- if (item.type === 'file' && !selectedFiles.includes(item.path)) {
731
+ fileList.forEach((item) => {
732
+ if (item.type === "file" && !selectedFiles.includes(item.path)) {
686
733
  selectedFiles.push(item.path);
687
734
  addedCount++;
688
735
  }
@@ -691,11 +738,11 @@ export async function selectFilesKeyboard(_rl, currentDir = process.cwd(), allow
691
738
  displayBrowser();
692
739
  }
693
740
  break;
694
- case 'c':
741
+ case "c":
695
742
  selectedFiles.length = 0;
696
743
  displayBrowser();
697
744
  break;
698
- case 'r':
745
+ case "r":
699
746
  refreshFileList();
700
747
  displayBrowser();
701
748
  break;
@@ -704,7 +751,7 @@ export async function selectFilesKeyboard(_rl, currentDir = process.cwd(), allow
704
751
  isNavigating = false;
705
752
  break;
706
753
  case KEYS.ESCAPE:
707
- case '\u001b':
754
+ case "\u001b":
708
755
  isNavigating = false;
709
756
  break;
710
757
  default:
@@ -721,10 +768,10 @@ export async function selectFilesKeyboard(_rl, currentDir = process.cwd(), allow
721
768
  const keyStr = key.toString();
722
769
  handleKeyInput(keyStr);
723
770
  if (!isNavigating) {
724
- process.stdin.removeListener('data', onData);
771
+ process.stdin.removeListener("data", onData);
725
772
  try {
726
773
  for (const l of prevDataListeners) {
727
- process.stdin.on('data', l);
774
+ process.stdin.on("data", l);
728
775
  }
729
776
  }
730
777
  catch {
@@ -734,8 +781,8 @@ export async function selectFilesKeyboard(_rl, currentDir = process.cwd(), allow
734
781
  }
735
782
  process.stdin.pause();
736
783
  if (selectedFiles.length > 0) {
737
- console.log(chalk.green.bold('✅ File Selection Complete!'));
738
- console.log(chalk.cyan('-'.repeat(50)));
784
+ console.log(chalk.green.bold("✅ File Selection Complete!"));
785
+ console.log(chalk.cyan("-".repeat(50)));
739
786
  const totalSize = selectedFiles.reduce((sum, file) => {
740
787
  try {
741
788
  return sum + fs.statSync(file).size;
@@ -748,19 +795,22 @@ export async function selectFilesKeyboard(_rl, currentDir = process.cwd(), allow
748
795
  selectedFiles.forEach((file, index) => {
749
796
  try {
750
797
  const stats = fs.statSync(file);
751
- const size = (stats.size / 1024).toFixed(1) + ' KB';
752
- console.log(pad(chalk.green(`${index + 1}.`), 5) + pad(path.basename(file), 35) + chalk.gray(size));
798
+ const size = (stats.size / 1024).toFixed(1) + " KB";
799
+ console.log(pad(chalk.green(`${index + 1}.`), 5) +
800
+ pad(path.basename(file), 35) +
801
+ chalk.gray(size));
753
802
  }
754
- catch (e) {
755
- console.log(pad(chalk.red(`${index + 1}.`), 5) + chalk.red(path.basename(file) + ' (Error reading file)'));
803
+ catch {
804
+ console.log(pad(chalk.red(`${index + 1}.`), 5) +
805
+ chalk.red(path.basename(file) + " (Error reading file)"));
756
806
  }
757
807
  });
758
- console.log(chalk.cyan('-'.repeat(50)));
808
+ console.log(chalk.cyan("-".repeat(50)));
759
809
  }
760
810
  resolve(selectedFiles);
761
811
  }
762
812
  };
763
- process.stdin.on('data', onData);
813
+ process.stdin.on("data", onData);
764
814
  });
765
815
  }
766
816
  //# sourceMappingURL=interactive.js.map