canvaslms-cli 1.6.2 → 1.6.4-fix

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