canvaslms-cli 1.6.2 → 1.6.3

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 +210 -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 +296 -176
  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 +21 -19
  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 +10 -4
  47. package/dist/lib/display.d.ts.map +1 -1
  48. package/dist/lib/display.js +263 -167
  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 +193 -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 +9 -4
  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,78 @@ 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
+ return str.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, "");
420
462
  }
421
- function printAndTrack(message = '') {
463
+ function printAndTrack(message = "") {
422
464
  console.log(message);
423
465
  const width = process.stdout.columns || 80;
424
466
  const clean = stripAnsi(message);
425
- const lines = clean.split('\n');
467
+ const lines = clean.split("\n");
426
468
  let count = 0;
427
469
  for (const line of lines) {
428
470
  count += Math.max(1, Math.ceil((line.length || 0.5) / width));
@@ -445,11 +487,11 @@ export async function selectFilesKeyboard(_rl, currentDir = process.cwd(), allow
445
487
  if (breadcrumb) {
446
488
  printAndTrack(breadcrumb);
447
489
  }
448
- printAndTrack(chalk.gray('💡 ↑↓←→:Navigate Space:Select Enter:Open/Finish Backspace:Up a:All c:Clear r:Reload Esc/Ctrl+C:Exit'));
490
+ printAndTrack(chalk.gray("💡 ↑↓←→:Navigate Space:Select Enter:Open/Finish Backspace:Up a:All c:Clear r:Reload Esc/Ctrl+C:Exit"));
449
491
  if (Array.isArray(allowedExtensions) && allowedExtensions.length > 0) {
450
492
  const exts = allowedExtensions
451
- .map(e => (e.startsWith('.') ? e.toLowerCase() : '.' + e.toLowerCase()))
452
- .join(', ');
493
+ .map((e) => e.startsWith(".") ? e.toLowerCase() : "." + e.toLowerCase())
494
+ .join(", ");
453
495
  printAndTrack(chalk.yellow(`Allowed: ${exts}`));
454
496
  }
455
497
  if (selectedFiles.length > 0) {
@@ -465,7 +507,7 @@ export async function selectFilesKeyboard(_rl, currentDir = process.cwd(), allow
465
507
  }
466
508
  printAndTrack();
467
509
  if (fileList.length === 0) {
468
- printAndTrack(chalk.yellow('📭 No files found in this directory.'));
510
+ printAndTrack(chalk.yellow("📭 No files found in this directory."));
469
511
  return;
470
512
  }
471
513
  displayFileTree();
@@ -479,36 +521,38 @@ export async function selectFilesKeyboard(_rl, currentDir = process.cwd(), allow
479
521
  if (startIdx > 0) {
480
522
  printAndTrack(chalk.gray(` ⋮ (${startIdx} items above)`));
481
523
  }
482
- const maxItemWidth = Math.max(...visibleItems.map(item => {
524
+ const maxItemWidth = Math.max(...visibleItems.map((item) => {
483
525
  const name = path.basename(item.path);
484
526
  return name.length + 4;
485
527
  }));
486
528
  const itemWidth = Math.min(Math.max(maxItemWidth, 15), 25);
487
529
  const columnsPerRow = Math.max(1, Math.floor((terminalWidth - 4) / itemWidth));
488
- let currentRow = '';
530
+ let currentRow = "";
489
531
  let itemsInCurrentRow = 0;
490
532
  visibleItems.forEach((item, index) => {
491
533
  const actualIndex = startIdx + index;
492
534
  const isSelected = selectedFiles.includes(item.path);
493
535
  const isCurrent = actualIndex === currentIndex;
494
- let icon = '';
495
- if (item.type === 'parent' || item.type === 'directory') {
496
- icon = '📁';
536
+ let icon = "";
537
+ if (item.type === "parent" || item.type === "directory") {
538
+ icon = "📁";
497
539
  }
498
540
  else {
499
541
  icon = getFileIcon(path.basename(item.path));
500
542
  }
501
543
  const name = item.name || path.basename(item.path);
502
- const truncatedName = name.length > itemWidth - 4 ? name.slice(0, itemWidth - 7) + '...' : name;
544
+ const truncatedName = name.length > itemWidth - 4
545
+ ? name.slice(0, itemWidth - 7) + "..."
546
+ : name;
503
547
  let itemDisplay = `${icon} ${truncatedName}`;
504
548
  if (isCurrent) {
505
549
  if (isSelected) {
506
550
  itemDisplay = chalk.black.bgGreen(` ${itemDisplay}`.padEnd(itemWidth - 1));
507
551
  }
508
- else if (item.type === 'parent') {
552
+ else if (item.type === "parent") {
509
553
  itemDisplay = chalk.white.bgBlue(` ${itemDisplay}`.padEnd(itemWidth - 1));
510
554
  }
511
- else if (item.type === 'directory') {
555
+ else if (item.type === "directory") {
512
556
  itemDisplay = chalk.black.bgCyan(` ${itemDisplay}`.padEnd(itemWidth - 1));
513
557
  }
514
558
  else {
@@ -519,10 +563,10 @@ export async function selectFilesKeyboard(_rl, currentDir = process.cwd(), allow
519
563
  if (isSelected) {
520
564
  itemDisplay = chalk.green(`✓${itemDisplay}`.padEnd(itemWidth));
521
565
  }
522
- else if (item.type === 'parent') {
566
+ else if (item.type === "parent") {
523
567
  itemDisplay = chalk.blue(` ${itemDisplay}`.padEnd(itemWidth));
524
568
  }
525
- else if (item.type === 'directory') {
569
+ else if (item.type === "directory") {
526
570
  itemDisplay = chalk.cyan(` ${itemDisplay}`.padEnd(itemWidth));
527
571
  }
528
572
  else {
@@ -531,9 +575,10 @@ export async function selectFilesKeyboard(_rl, currentDir = process.cwd(), allow
531
575
  }
532
576
  currentRow += itemDisplay;
533
577
  itemsInCurrentRow++;
534
- if (itemsInCurrentRow >= columnsPerRow || index === visibleItems.length - 1) {
578
+ if (itemsInCurrentRow >= columnsPerRow ||
579
+ index === visibleItems.length - 1) {
535
580
  printAndTrack(currentRow);
536
- currentRow = '';
581
+ currentRow = "";
537
582
  itemsInCurrentRow = 0;
538
583
  }
539
584
  });
@@ -555,39 +600,40 @@ export async function selectFilesKeyboard(_rl, currentDir = process.cwd(), allow
555
600
  try {
556
601
  if (currentPath !== currentDir) {
557
602
  fileList.push({
558
- type: 'parent',
603
+ type: "parent",
559
604
  path: path.dirname(currentPath),
560
- name: '..'
605
+ name: "..",
561
606
  });
562
607
  }
563
608
  const entries = fs.readdirSync(currentPath).sort();
564
- entries.forEach(entry => {
609
+ entries.forEach((entry) => {
565
610
  const fullPath = path.join(currentPath, entry);
566
611
  const stat = fs.statSync(fullPath);
567
612
  if (stat.isDirectory()) {
568
613
  fileList.push({
569
- type: 'directory',
614
+ type: "directory",
570
615
  path: fullPath,
571
- name: entry
616
+ name: entry,
572
617
  });
573
618
  }
574
619
  });
575
- entries.forEach(entry => {
620
+ entries.forEach((entry) => {
576
621
  const fullPath = path.join(currentPath, entry);
577
622
  const stat = fs.statSync(fullPath);
578
623
  if (stat.isFile()) {
579
- if (Array.isArray(allowedExtensions) && allowedExtensions.length > 0) {
580
- const lowerExts = allowedExtensions.map(e => (e.startsWith('.') ? e.toLowerCase() : '.' + e.toLowerCase()));
624
+ if (Array.isArray(allowedExtensions) &&
625
+ allowedExtensions.length > 0) {
626
+ const lowerExts = allowedExtensions.map((e) => e.startsWith(".") ? e.toLowerCase() : "." + e.toLowerCase());
581
627
  const ext = path.extname(entry).toLowerCase();
582
628
  if (!lowerExts.includes(ext)) {
583
629
  return;
584
630
  }
585
631
  }
586
632
  fileList.push({
587
- type: 'file',
633
+ type: "file",
588
634
  path: fullPath,
589
635
  name: entry,
590
- size: stat.size
636
+ size: stat.size,
591
637
  });
592
638
  }
593
639
  });
@@ -596,13 +642,13 @@ export async function selectFilesKeyboard(_rl, currentDir = process.cwd(), allow
596
642
  }
597
643
  }
598
644
  catch (error) {
599
- console.error('Error reading directory:', error);
645
+ console.error("Error reading directory:", error);
600
646
  fileList = [];
601
647
  }
602
648
  }
603
649
  function handleKeyInput(key) {
604
650
  const terminalWidth = process.stdout.columns || 80;
605
- const maxItemWidth = Math.max(...fileList.map(item => {
651
+ const maxItemWidth = Math.max(...fileList.map((item) => {
606
652
  const name = path.basename(item.path);
607
653
  return name.length + 4;
608
654
  }));
@@ -638,7 +684,7 @@ export async function selectFilesKeyboard(_rl, currentDir = process.cwd(), allow
638
684
  case KEYS.SPACE:
639
685
  if (fileList.length > 0) {
640
686
  const item = fileList[currentIndex];
641
- if (item && item.type === 'file') {
687
+ if (item && item.type === "file") {
642
688
  const index = selectedFiles.indexOf(item.path);
643
689
  if (index === -1) {
644
690
  selectedFiles.push(item.path);
@@ -653,7 +699,7 @@ export async function selectFilesKeyboard(_rl, currentDir = process.cwd(), allow
653
699
  case KEYS.ENTER:
654
700
  if (fileList.length > 0) {
655
701
  const item = fileList[currentIndex];
656
- if (item && (item.type === 'parent' || item.type === 'directory')) {
702
+ if (item && (item.type === "parent" || item.type === "directory")) {
657
703
  currentPath = item.path;
658
704
  currentIndex = 0;
659
705
  refreshFileList();
@@ -679,10 +725,10 @@ export async function selectFilesKeyboard(_rl, currentDir = process.cwd(), allow
679
725
  displayBrowser();
680
726
  }
681
727
  break;
682
- case 'a':
728
+ case "a":
683
729
  let addedCount = 0;
684
- fileList.forEach(item => {
685
- if (item.type === 'file' && !selectedFiles.includes(item.path)) {
730
+ fileList.forEach((item) => {
731
+ if (item.type === "file" && !selectedFiles.includes(item.path)) {
686
732
  selectedFiles.push(item.path);
687
733
  addedCount++;
688
734
  }
@@ -691,11 +737,11 @@ export async function selectFilesKeyboard(_rl, currentDir = process.cwd(), allow
691
737
  displayBrowser();
692
738
  }
693
739
  break;
694
- case 'c':
740
+ case "c":
695
741
  selectedFiles.length = 0;
696
742
  displayBrowser();
697
743
  break;
698
- case 'r':
744
+ case "r":
699
745
  refreshFileList();
700
746
  displayBrowser();
701
747
  break;
@@ -704,7 +750,7 @@ export async function selectFilesKeyboard(_rl, currentDir = process.cwd(), allow
704
750
  isNavigating = false;
705
751
  break;
706
752
  case KEYS.ESCAPE:
707
- case '\u001b':
753
+ case "\u001b":
708
754
  isNavigating = false;
709
755
  break;
710
756
  default:
@@ -721,10 +767,10 @@ export async function selectFilesKeyboard(_rl, currentDir = process.cwd(), allow
721
767
  const keyStr = key.toString();
722
768
  handleKeyInput(keyStr);
723
769
  if (!isNavigating) {
724
- process.stdin.removeListener('data', onData);
770
+ process.stdin.removeListener("data", onData);
725
771
  try {
726
772
  for (const l of prevDataListeners) {
727
- process.stdin.on('data', l);
773
+ process.stdin.on("data", l);
728
774
  }
729
775
  }
730
776
  catch {
@@ -734,8 +780,8 @@ export async function selectFilesKeyboard(_rl, currentDir = process.cwd(), allow
734
780
  }
735
781
  process.stdin.pause();
736
782
  if (selectedFiles.length > 0) {
737
- console.log(chalk.green.bold('✅ File Selection Complete!'));
738
- console.log(chalk.cyan('-'.repeat(50)));
783
+ console.log(chalk.green.bold("✅ File Selection Complete!"));
784
+ console.log(chalk.cyan("-".repeat(50)));
739
785
  const totalSize = selectedFiles.reduce((sum, file) => {
740
786
  try {
741
787
  return sum + fs.statSync(file).size;
@@ -748,19 +794,22 @@ export async function selectFilesKeyboard(_rl, currentDir = process.cwd(), allow
748
794
  selectedFiles.forEach((file, index) => {
749
795
  try {
750
796
  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));
797
+ const size = (stats.size / 1024).toFixed(1) + " KB";
798
+ console.log(pad(chalk.green(`${index + 1}.`), 5) +
799
+ pad(path.basename(file), 35) +
800
+ chalk.gray(size));
753
801
  }
754
- catch (e) {
755
- console.log(pad(chalk.red(`${index + 1}.`), 5) + chalk.red(path.basename(file) + ' (Error reading file)'));
802
+ catch {
803
+ console.log(pad(chalk.red(`${index + 1}.`), 5) +
804
+ chalk.red(path.basename(file) + " (Error reading file)"));
756
805
  }
757
806
  });
758
- console.log(chalk.cyan('-'.repeat(50)));
807
+ console.log(chalk.cyan("-".repeat(50)));
759
808
  }
760
809
  resolve(selectedFiles);
761
810
  }
762
811
  };
763
- process.stdin.on('data', onData);
812
+ process.stdin.on("data", onData);
764
813
  });
765
814
  }
766
815
  //# sourceMappingURL=interactive.js.map