@night-slayer18/leetcode-cli 1.6.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +86 -0
  2. package/dist/index.js +1565 -564
  3. package/package.json +4 -1
package/dist/index.js CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  // src/index.ts
4
4
  import { Command } from "commander";
5
- import chalk22 from "chalk";
5
+ import chalk26 from "chalk";
6
6
 
7
7
  // src/commands/login.ts
8
8
  import inquirer from "inquirer";
@@ -571,7 +571,7 @@ async function whoamiCommand() {
571
571
 
572
572
  // src/commands/list.ts
573
573
  import ora2 from "ora";
574
- import chalk4 from "chalk";
574
+ import chalk5 from "chalk";
575
575
 
576
576
  // src/utils/auth.ts
577
577
  import chalk2 from "chalk";
@@ -596,16 +596,227 @@ async function requireAuth() {
596
596
  }
597
597
 
598
598
  // src/utils/display.ts
599
- import chalk3 from "chalk";
599
+ import chalk4 from "chalk";
600
600
  import Table from "cli-table3";
601
+
602
+ // src/utils/visualize.ts
603
+ import chalk3 from "chalk";
604
+ var TAG_VISUALIZATION = {
605
+ "Linked List": "linkedlist",
606
+ "Doubly-Linked List": "linkedlist",
607
+ "Tree": "tree",
608
+ "Binary Tree": "tree",
609
+ "Binary Search Tree": "tree",
610
+ "Trie": "tree",
611
+ "Segment Tree": "tree",
612
+ "Binary Indexed Tree": "tree",
613
+ "Graph": "graph",
614
+ "Matrix": "matrix",
615
+ "Array": "array",
616
+ "Hash Table": "array",
617
+ "Stack": "array",
618
+ "Queue": "array",
619
+ "Monotonic Stack": "array",
620
+ "Monotonic Queue": "array",
621
+ "Heap (Priority Queue)": "array",
622
+ "String": "string"
623
+ };
624
+ function detectVisualizationType(tags) {
625
+ for (const tag of tags) {
626
+ const vizType = TAG_VISUALIZATION[tag.name];
627
+ if (vizType) return vizType;
628
+ }
629
+ return null;
630
+ }
631
+ function parseValue(value) {
632
+ try {
633
+ return JSON.parse(value);
634
+ } catch {
635
+ return value;
636
+ }
637
+ }
638
+ function isMatrix(value) {
639
+ return Array.isArray(value) && value.length > 0 && Array.isArray(value[0]);
640
+ }
641
+ function visualizeArray(arr, expected) {
642
+ if (!Array.isArray(arr) || arr.length === 0) {
643
+ return String(arr);
644
+ }
645
+ const maxLen = Math.max(...arr.map((v) => String(v).length), 1);
646
+ const cellWidth = Math.max(maxLen, 3);
647
+ const indices = arr.map((_, i) => `[${i}]`.padStart(cellWidth).padEnd(cellWidth)).join(" ");
648
+ const values = arr.map((v, i) => {
649
+ const valStr = String(v).padStart(cellWidth).padEnd(cellWidth);
650
+ if (expected && Array.isArray(expected) && expected[i] !== v) {
651
+ return chalk3.red.bold(valStr);
652
+ }
653
+ return valStr;
654
+ }).join(" ");
655
+ return `${chalk3.gray(indices)}
656
+ ${values}`;
657
+ }
658
+ function visualizeLinkedList(arr, expected) {
659
+ if (!Array.isArray(arr)) {
660
+ return String(arr);
661
+ }
662
+ if (arr.length === 0) {
663
+ return chalk3.gray("(empty)");
664
+ }
665
+ const parts = arr.map((v, i) => {
666
+ const valStr = String(v);
667
+ if (expected && Array.isArray(expected)) {
668
+ if (i >= expected.length || expected[i] !== v) {
669
+ return chalk3.red.bold(valStr);
670
+ }
671
+ }
672
+ return valStr;
673
+ });
674
+ return parts.join(chalk3.gray(" \u2192 "));
675
+ }
676
+ function visualizeTree(arr) {
677
+ if (!Array.isArray(arr) || arr.length === 0) {
678
+ return chalk3.gray("(empty tree)");
679
+ }
680
+ const lines = [];
681
+ const height = Math.floor(Math.log2(arr.length)) + 1;
682
+ const maxWidth = Math.pow(2, height) * 3;
683
+ function renderLevel(level, startIdx, endIdx, indent) {
684
+ if (startIdx > arr.length - 1) return;
685
+ const levelNodes = [];
686
+ const levelBranches = [];
687
+ const spacing = Math.floor(maxWidth / Math.pow(2, level + 1));
688
+ for (let i = startIdx; i <= endIdx && i < arr.length; i++) {
689
+ const val = arr[i];
690
+ const nodeStr = val === null ? " " : String(val);
691
+ levelNodes.push(nodeStr.padStart(spacing).padEnd(spacing));
692
+ const leftChild = 2 * i + 1;
693
+ const rightChild = 2 * i + 2;
694
+ const hasLeft = leftChild < arr.length && arr[leftChild] !== null;
695
+ const hasRight = rightChild < arr.length && arr[rightChild] !== null;
696
+ if (hasLeft || hasRight) {
697
+ let branch = "";
698
+ if (hasLeft) branch += "/";
699
+ else branch += " ";
700
+ branch += " ";
701
+ if (hasRight) branch += "\\";
702
+ else branch += " ";
703
+ levelBranches.push(branch.padStart(spacing).padEnd(spacing));
704
+ }
705
+ }
706
+ if (levelNodes.length > 0) {
707
+ lines.push(levelNodes.join(""));
708
+ if (levelBranches.length > 0 && level < height - 1) {
709
+ lines.push(levelBranches.join(""));
710
+ }
711
+ }
712
+ }
713
+ for (let level = 0; level < height; level++) {
714
+ const startIdx = Math.pow(2, level) - 1;
715
+ const endIdx = Math.pow(2, level + 1) - 2;
716
+ renderLevel(level, startIdx, endIdx, 0);
717
+ }
718
+ return lines.join("\n");
719
+ }
720
+ function visualizeMatrix(matrix, expected) {
721
+ if (!isMatrix(matrix) || matrix.length === 0) {
722
+ return String(matrix);
723
+ }
724
+ const rows = matrix.length;
725
+ const cols = matrix[0].length;
726
+ const cellWidth = 3;
727
+ const lines = [];
728
+ const colHeaders = " " + matrix[0].map((_, i) => String(i).padStart(cellWidth).padEnd(cellWidth)).join(" ");
729
+ lines.push(chalk3.gray(colHeaders));
730
+ lines.push(" \u250C" + Array(cols).fill("\u2500\u2500\u2500").join("\u252C") + "\u2510");
731
+ for (let r = 0; r < rows; r++) {
732
+ const rowContent = matrix[r].map((v, c) => {
733
+ const valStr = String(v).padStart(2);
734
+ if (expected && isMatrix(expected) && expected[r] && expected[r][c] !== v) {
735
+ return chalk3.red.bold(valStr);
736
+ }
737
+ return valStr;
738
+ }).join(" \u2502 ");
739
+ lines.push(chalk3.gray(` ${r} `) + `\u2502 ${rowContent} \u2502`);
740
+ if (r < rows - 1) {
741
+ lines.push(" \u251C" + Array(cols).fill("\u2500\u2500\u2500").join("\u253C") + "\u2524");
742
+ } else {
743
+ lines.push(" \u2514" + Array(cols).fill("\u2500\u2500\u2500").join("\u2534") + "\u2518");
744
+ }
745
+ }
746
+ return lines.join("\n");
747
+ }
748
+ function visualizeGraph(adjList) {
749
+ if (!isMatrix(adjList)) {
750
+ return String(adjList);
751
+ }
752
+ const lines = adjList.map((neighbors, node) => {
753
+ const neighborStr = Array.isArray(neighbors) ? neighbors.join(", ") : String(neighbors);
754
+ return ` ${chalk3.cyan(String(node))} \u2192 [${neighborStr}]`;
755
+ });
756
+ return lines.join("\n");
757
+ }
758
+ function visualizeTestOutput(output, expected, tags) {
759
+ const outputVal = parseValue(output);
760
+ const expectedVal = parseValue(expected);
761
+ const matches = output === expected;
762
+ const vizType = detectVisualizationType(tags);
763
+ let outputVis;
764
+ let expectedVis;
765
+ if (isMatrix(outputVal)) {
766
+ const expectedMatrix = isMatrix(expectedVal) ? expectedVal : void 0;
767
+ outputVis = visualizeMatrix(outputVal, expectedMatrix);
768
+ expectedVis = isMatrix(expectedVal) ? visualizeMatrix(expectedVal) : String(expected);
769
+ return { outputVis, expectedVis, matches };
770
+ }
771
+ if (vizType === null) {
772
+ return {
773
+ outputVis: String(output),
774
+ expectedVis: String(expected),
775
+ matches,
776
+ unsupported: true
777
+ };
778
+ }
779
+ switch (vizType) {
780
+ case "linkedlist":
781
+ outputVis = visualizeLinkedList(outputVal, expectedVal);
782
+ expectedVis = visualizeLinkedList(expectedVal);
783
+ break;
784
+ case "tree":
785
+ outputVis = visualizeTree(outputVal);
786
+ expectedVis = visualizeTree(expectedVal);
787
+ break;
788
+ case "graph":
789
+ outputVis = visualizeGraph(outputVal);
790
+ expectedVis = visualizeGraph(expectedVal);
791
+ break;
792
+ case "matrix":
793
+ const expMatrix = isMatrix(expectedVal) ? expectedVal : void 0;
794
+ outputVis = visualizeMatrix(outputVal, expMatrix);
795
+ expectedVis = isMatrix(expectedVal) ? visualizeMatrix(expectedVal) : String(expected);
796
+ break;
797
+ case "array":
798
+ case "string":
799
+ if (Array.isArray(outputVal)) {
800
+ outputVis = visualizeArray(outputVal, expectedVal);
801
+ expectedVis = Array.isArray(expectedVal) ? visualizeArray(expectedVal) : String(expected);
802
+ } else {
803
+ outputVis = matches ? String(output) : chalk3.red.bold(String(output));
804
+ expectedVis = String(expected);
805
+ }
806
+ break;
807
+ }
808
+ return { outputVis, expectedVis, matches };
809
+ }
810
+
811
+ // src/utils/display.ts
601
812
  function displayProblemList(problems, total) {
602
813
  const table = new Table({
603
814
  head: [
604
- chalk3.cyan("ID"),
605
- chalk3.cyan("Title"),
606
- chalk3.cyan("Difficulty"),
607
- chalk3.cyan("Rate"),
608
- chalk3.cyan("Status")
815
+ chalk4.cyan("ID"),
816
+ chalk4.cyan("Title"),
817
+ chalk4.cyan("Difficulty"),
818
+ chalk4.cyan("Rate"),
819
+ chalk4.cyan("Status")
609
820
  ],
610
821
  colWidths: [8, 45, 12, 10, 10],
611
822
  style: { head: [], border: [] }
@@ -624,34 +835,34 @@ function displayProblemList(problems, total) {
624
835
  ]);
625
836
  }
626
837
  console.log(table.toString());
627
- console.log(chalk3.gray(`
838
+ console.log(chalk4.gray(`
628
839
  Showing ${problems.length} of ${total} problems`));
629
840
  }
630
841
  function displayProblemDetail(problem) {
631
842
  console.log();
632
843
  const titlePrefix = problem.isPaidOnly ? "\u{1F512} " : "";
633
- console.log(chalk3.bold.cyan(` ${problem.questionFrontendId}. ${titlePrefix}${problem.title}`));
844
+ console.log(chalk4.bold.cyan(` ${problem.questionFrontendId}. ${titlePrefix}${problem.title}`));
634
845
  console.log(` ${colorDifficulty(problem.difficulty)}`);
635
- console.log(chalk3.gray(` https://leetcode.com/problems/${problem.titleSlug}/`));
846
+ console.log(chalk4.gray(` https://leetcode.com/problems/${problem.titleSlug}/`));
636
847
  console.log();
637
848
  if (problem.isPaidOnly) {
638
- console.log(chalk3.yellow(" \u26A0\uFE0F Premium Problem"));
639
- console.log(chalk3.gray(" This problem requires a LeetCode Premium subscription."));
640
- console.log(chalk3.gray(` Visit the URL above to view on LeetCode.`));
849
+ console.log(chalk4.yellow(" \u26A0\uFE0F Premium Problem"));
850
+ console.log(chalk4.gray(" This problem requires a LeetCode Premium subscription."));
851
+ console.log(chalk4.gray(` Visit the URL above to view on LeetCode.`));
641
852
  console.log();
642
853
  }
643
854
  if (problem.topicTags.length) {
644
- const tags = problem.topicTags.map((t) => chalk3.bgBlue.white(` ${t.name} `)).join(" ");
855
+ const tags = problem.topicTags.map((t) => chalk4.bgBlue.white(` ${t.name} `)).join(" ");
645
856
  console.log(` ${tags}`);
646
857
  console.log();
647
858
  }
648
- console.log(chalk3.gray("\u2500".repeat(60)));
859
+ console.log(chalk4.gray("\u2500".repeat(60)));
649
860
  console.log();
650
861
  let content = problem.content;
651
862
  if (!content) {
652
- console.log(chalk3.yellow(" \u{1F512} Premium Content"));
653
- console.log(chalk3.gray(" Problem description is not available directly."));
654
- console.log(chalk3.gray(" Please visit the URL above to view on LeetCode."));
863
+ console.log(chalk4.yellow(" \u{1F512} Premium Content"));
864
+ console.log(chalk4.gray(" Problem description is not available directly."));
865
+ console.log(chalk4.gray(" Please visit the URL above to view on LeetCode."));
655
866
  console.log();
656
867
  return;
657
868
  }
@@ -671,100 +882,128 @@ function displayProblemDetail(problem) {
671
882
  content = content.replace(/<[^>]+>/g, "");
672
883
  content = content.replace(/&nbsp;/g, " ").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&le;/g, "\u2264").replace(/&ge;/g, "\u2265").replace(/&#(\d+);/g, (_, code) => String.fromCharCode(parseInt(code, 10)));
673
884
  content = content.replace(/\n{3,}/g, "\n\n").trim();
674
- content = content.replace(/§EXAMPLE§(\d+)§/g, (_, num) => chalk3.green.bold(`\u{1F4CC} Example ${num}:`));
675
- content = content.replace(/§INPUT§/g, chalk3.yellow("Input:"));
676
- content = content.replace(/§OUTPUT§/g, chalk3.yellow("Output:"));
677
- content = content.replace(/§EXPLAIN§/g, chalk3.gray("Explanation:"));
678
- content = content.replace(/§CONSTRAINTS§/g, chalk3.cyan.bold("\n\u{1F4CB} Constraints:"));
679
- content = content.replace(/§FOLLOWUP§/g, chalk3.magenta.bold("\n\u{1F4A1} Follow-up:"));
885
+ content = content.replace(/§EXAMPLE§(\d+)§/g, (_, num) => chalk4.green.bold(`\u{1F4CC} Example ${num}:`));
886
+ content = content.replace(/§INPUT§/g, chalk4.yellow("Input:"));
887
+ content = content.replace(/§OUTPUT§/g, chalk4.yellow("Output:"));
888
+ content = content.replace(/§EXPLAIN§/g, chalk4.gray("Explanation:"));
889
+ content = content.replace(/§CONSTRAINTS§/g, chalk4.cyan.bold("\n\u{1F4CB} Constraints:"));
890
+ content = content.replace(/§FOLLOWUP§/g, chalk4.magenta.bold("\n\u{1F4A1} Follow-up:"));
680
891
  console.log(content);
681
892
  console.log();
682
893
  }
683
- function displayTestResult(result) {
894
+ function displayTestResult(result, topicTags) {
684
895
  console.log();
685
896
  if (result.compile_error) {
686
- console.log(chalk3.red.bold("\u274C Compile Error"));
687
- console.log(chalk3.red(result.compile_error));
897
+ console.log(chalk4.red.bold("\u274C Compile Error"));
898
+ console.log(chalk4.red(result.compile_error));
688
899
  return;
689
900
  }
690
901
  if (result.runtime_error) {
691
- console.log(chalk3.red.bold("\u274C Runtime Error"));
692
- console.log(chalk3.red(result.runtime_error));
902
+ console.log(chalk4.red.bold("\u274C Runtime Error"));
903
+ console.log(chalk4.red(result.runtime_error));
693
904
  return;
694
905
  }
695
906
  if (result.correct_answer) {
696
- console.log(chalk3.green.bold("\u2713 All test cases passed!"));
907
+ console.log(chalk4.green.bold("\u2713 All test cases passed!"));
697
908
  } else {
698
- console.log(chalk3.yellow.bold("\u2717 Some test cases failed"));
699
- }
700
- console.log();
701
- console.log(chalk3.gray("Your Output:"));
702
- for (const output of result.code_answer ?? []) {
703
- console.log(chalk3.white(` ${output}`));
909
+ console.log(chalk4.yellow.bold("\u2717 Some test cases failed"));
704
910
  }
705
- console.log();
706
- console.log(chalk3.gray("Expected Output:"));
707
- for (const output of result.expected_code_answer ?? []) {
708
- console.log(chalk3.white(` ${output}`));
911
+ const outputs = result.code_answer ?? [];
912
+ const expected = result.expected_code_answer ?? [];
913
+ if (topicTags && outputs.length > 0) {
914
+ console.log();
915
+ console.log(chalk4.gray.bold("\u2500".repeat(50)));
916
+ const validCases = outputs.map((out, i) => ({ out, exp: expected[i] ?? "" })).filter(({ out, exp }) => out !== "" || exp !== "");
917
+ for (let i = 0; i < validCases.length; i++) {
918
+ const { out, exp } = validCases[i];
919
+ const { outputVis, expectedVis, matches, unsupported } = visualizeTestOutput(out, exp, topicTags);
920
+ console.log();
921
+ console.log(chalk4.gray(`Test Case ${i + 1}:`));
922
+ if (unsupported) {
923
+ console.log(chalk4.yellow(" \u26A0 No visualization available for this problem type"));
924
+ console.log(chalk4.gray(` Tags: ${topicTags.map((t) => t.name).join(", ")}`));
925
+ }
926
+ console.log();
927
+ console.log(chalk4.cyan(" Your Output:"));
928
+ outputVis.split("\n").forEach((line) => console.log(` ${line}`));
929
+ console.log();
930
+ console.log(chalk4.cyan(" Expected:"));
931
+ expectedVis.split("\n").forEach((line) => console.log(` ${line}`));
932
+ console.log();
933
+ console.log(matches ? chalk4.green(" \u2713 Match") : chalk4.red(" \u2717 Mismatch"));
934
+ }
935
+ console.log(chalk4.gray.bold("\u2500".repeat(50)));
936
+ } else {
937
+ console.log();
938
+ console.log(chalk4.gray("Your Output:"));
939
+ for (const output of outputs) {
940
+ console.log(chalk4.white(` ${output}`));
941
+ }
942
+ console.log();
943
+ console.log(chalk4.gray("Expected Output:"));
944
+ for (const output of expected) {
945
+ console.log(chalk4.white(` ${output}`));
946
+ }
709
947
  }
710
- if (result.std_output_list?.length) {
948
+ const stdoutEntries = (result.std_output_list ?? []).filter((s) => s);
949
+ if (stdoutEntries.length > 0) {
711
950
  console.log();
712
- console.log(chalk3.gray("Stdout:"));
713
- for (const output of result.std_output_list) {
714
- if (output) console.log(chalk3.gray(` ${output}`));
951
+ console.log(chalk4.gray("Stdout:"));
952
+ for (const output of stdoutEntries) {
953
+ console.log(chalk4.gray(` ${output}`));
715
954
  }
716
955
  }
717
956
  }
718
957
  function displaySubmissionResult(result) {
719
958
  console.log();
720
959
  if (result.compile_error) {
721
- console.log(chalk3.red.bold("\u274C Compile Error"));
722
- console.log(chalk3.red(result.compile_error));
960
+ console.log(chalk4.red.bold("\u274C Compile Error"));
961
+ console.log(chalk4.red(result.compile_error));
723
962
  return;
724
963
  }
725
964
  if (result.runtime_error) {
726
- console.log(chalk3.red.bold("\u274C Runtime Error"));
727
- console.log(chalk3.red(result.runtime_error));
965
+ console.log(chalk4.red.bold("\u274C Runtime Error"));
966
+ console.log(chalk4.red(result.runtime_error));
728
967
  if (result.last_testcase) {
729
- console.log(chalk3.gray("Last testcase:"), result.last_testcase);
968
+ console.log(chalk4.gray("Last testcase:"), result.last_testcase);
730
969
  }
731
970
  return;
732
971
  }
733
972
  if (result.status_msg === "Accepted") {
734
- console.log(chalk3.green.bold("\u2713 Accepted!"));
973
+ console.log(chalk4.green.bold("\u2713 Accepted!"));
735
974
  console.log();
736
975
  console.log(
737
- chalk3.gray("Runtime:"),
738
- chalk3.white(result.status_runtime),
739
- chalk3.gray(`(beats ${result.runtime_percentile?.toFixed(1) ?? "N/A"}%)`)
976
+ chalk4.gray("Runtime:"),
977
+ chalk4.white(result.status_runtime),
978
+ chalk4.gray(`(beats ${result.runtime_percentile?.toFixed(1) ?? "N/A"}%)`)
740
979
  );
741
980
  console.log(
742
- chalk3.gray("Memory:"),
743
- chalk3.white(result.status_memory),
744
- chalk3.gray(`(beats ${result.memory_percentile?.toFixed(1) ?? "N/A"}%)`)
981
+ chalk4.gray("Memory:"),
982
+ chalk4.white(result.status_memory),
983
+ chalk4.gray(`(beats ${result.memory_percentile?.toFixed(1) ?? "N/A"}%)`)
745
984
  );
746
985
  } else {
747
- console.log(chalk3.red.bold(`\u274C ${result.status_msg}`));
986
+ console.log(chalk4.red.bold(`\u274C ${result.status_msg}`));
748
987
  console.log();
749
- console.log(chalk3.gray(`Passed ${result.total_correct}/${result.total_testcases} testcases`));
988
+ console.log(chalk4.gray(`Passed ${result.total_correct}/${result.total_testcases} testcases`));
750
989
  if (result.code_output) {
751
- console.log(chalk3.gray("Your Output:"), result.code_output);
990
+ console.log(chalk4.gray("Your Output:"), result.code_output);
752
991
  }
753
992
  if (result.expected_output) {
754
- console.log(chalk3.gray("Expected:"), result.expected_output);
993
+ console.log(chalk4.gray("Expected:"), result.expected_output);
755
994
  }
756
995
  if (result.last_testcase) {
757
- console.log(chalk3.gray("Failed testcase:"), result.last_testcase);
996
+ console.log(chalk4.gray("Failed testcase:"), result.last_testcase);
758
997
  }
759
998
  }
760
999
  }
761
1000
  function displayUserStats(username, realName, ranking, acStats, streak, totalActiveDays) {
762
1001
  console.log();
763
- console.log(chalk3.bold.white(`\u{1F464} ${username}`) + (realName ? chalk3.gray(` (${realName})`) : ""));
764
- console.log(chalk3.gray(`Ranking: #${ranking.toLocaleString()}`));
1002
+ console.log(chalk4.bold.white(`\u{1F464} ${username}`) + (realName ? chalk4.gray(` (${realName})`) : ""));
1003
+ console.log(chalk4.gray(`Ranking: #${ranking.toLocaleString()}`));
765
1004
  console.log();
766
1005
  const table = new Table({
767
- head: [chalk3.cyan("Difficulty"), chalk3.cyan("Solved")],
1006
+ head: [chalk4.cyan("Difficulty"), chalk4.cyan("Solved")],
768
1007
  style: { head: [], border: [] }
769
1008
  });
770
1009
  for (const stat of acStats) {
@@ -776,33 +1015,33 @@ function displayUserStats(username, realName, ranking, acStats, streak, totalAct
776
1015
  }
777
1016
  }
778
1017
  const total = acStats.find((s) => s.difficulty === "All")?.count ?? 0;
779
- table.push([chalk3.white.bold("Total"), chalk3.white.bold(total.toString())]);
1018
+ table.push([chalk4.white.bold("Total"), chalk4.white.bold(total.toString())]);
780
1019
  console.log(table.toString());
781
1020
  console.log();
782
- console.log(chalk3.gray("\u{1F525} Current streak:"), chalk3.hex("#FFA500")(streak.toString()), chalk3.gray("days"));
783
- console.log(chalk3.gray("\u{1F4C5} Total active days:"), chalk3.white(totalActiveDays.toString()));
1021
+ console.log(chalk4.gray("\u{1F525} Current streak:"), chalk4.hex("#FFA500")(streak.toString()), chalk4.gray("days"));
1022
+ console.log(chalk4.gray("\u{1F4C5} Total active days:"), chalk4.white(totalActiveDays.toString()));
784
1023
  }
785
1024
  function displayDailyChallenge(date, problem) {
786
1025
  console.log();
787
- console.log(chalk3.bold.yellow("\u{1F3AF} Daily Challenge"), chalk3.gray(`(${date})`));
1026
+ console.log(chalk4.bold.yellow("\u{1F3AF} Daily Challenge"), chalk4.gray(`(${date})`));
788
1027
  console.log();
789
- console.log(chalk3.white(`${problem.questionFrontendId}. ${problem.title}`));
1028
+ console.log(chalk4.white(`${problem.questionFrontendId}. ${problem.title}`));
790
1029
  console.log(colorDifficulty(problem.difficulty));
791
- console.log(chalk3.gray(`https://leetcode.com/problems/${problem.titleSlug}/`));
1030
+ console.log(chalk4.gray(`https://leetcode.com/problems/${problem.titleSlug}/`));
792
1031
  if (problem.topicTags.length) {
793
1032
  console.log();
794
- const tags = problem.topicTags.map((t) => chalk3.blue(t.name)).join(" ");
795
- console.log(chalk3.gray("Tags:"), tags);
1033
+ const tags = problem.topicTags.map((t) => chalk4.blue(t.name)).join(" ");
1034
+ console.log(chalk4.gray("Tags:"), tags);
796
1035
  }
797
1036
  }
798
1037
  function colorDifficulty(difficulty) {
799
1038
  switch (difficulty.toLowerCase()) {
800
1039
  case "easy":
801
- return chalk3.green(difficulty);
1040
+ return chalk4.green(difficulty);
802
1041
  case "medium":
803
- return chalk3.yellow(difficulty);
1042
+ return chalk4.yellow(difficulty);
804
1043
  case "hard":
805
- return chalk3.red(difficulty);
1044
+ return chalk4.red(difficulty);
806
1045
  default:
807
1046
  return difficulty;
808
1047
  }
@@ -810,22 +1049,22 @@ function colorDifficulty(difficulty) {
810
1049
  function formatStatus(status) {
811
1050
  switch (status) {
812
1051
  case "ac":
813
- return chalk3.green("\u2713");
1052
+ return chalk4.green("\u2713");
814
1053
  case "notac":
815
- return chalk3.yellow("\u25CB");
1054
+ return chalk4.yellow("\u25CB");
816
1055
  default:
817
- return chalk3.gray("-");
1056
+ return chalk4.gray("-");
818
1057
  }
819
1058
  }
820
1059
  function displaySubmissionsList(submissions) {
821
1060
  const table = new Table({
822
1061
  head: [
823
- chalk3.cyan("ID"),
824
- chalk3.cyan("Status"),
825
- chalk3.cyan("Lang"),
826
- chalk3.cyan("Runtime"),
827
- chalk3.cyan("Memory"),
828
- chalk3.cyan("Date")
1062
+ chalk4.cyan("ID"),
1063
+ chalk4.cyan("Status"),
1064
+ chalk4.cyan("Lang"),
1065
+ chalk4.cyan("Runtime"),
1066
+ chalk4.cyan("Memory"),
1067
+ chalk4.cyan("Date")
829
1068
  ],
830
1069
  colWidths: [12, 18, 15, 12, 12, 25],
831
1070
  style: { head: [], border: [] }
@@ -835,7 +1074,7 @@ function displaySubmissionsList(submissions) {
835
1074
  const cleanTime = new Date(parseInt(s.timestamp) * 1e3).toLocaleString();
836
1075
  table.push([
837
1076
  s.id,
838
- isAC ? chalk3.green(s.statusDisplay) : chalk3.red(s.statusDisplay),
1077
+ isAC ? chalk4.green(s.statusDisplay) : chalk4.red(s.statusDisplay),
839
1078
  s.lang,
840
1079
  s.runtime,
841
1080
  s.memory,
@@ -886,25 +1125,25 @@ async function listCommand(options) {
886
1125
  const { total, problems } = await leetcodeClient.getProblems(filters);
887
1126
  spinner.stop();
888
1127
  if (problems.length === 0) {
889
- console.log(chalk4.yellow("No problems found matching your criteria."));
1128
+ console.log(chalk5.yellow("No problems found matching your criteria."));
890
1129
  return;
891
1130
  }
892
1131
  displayProblemList(problems, total);
893
1132
  if (page * limit < total) {
894
- console.log(chalk4.gray(`
1133
+ console.log(chalk5.gray(`
895
1134
  Page ${page} of ${Math.ceil(total / limit)}. Use --page to navigate.`));
896
1135
  }
897
1136
  } catch (error) {
898
1137
  spinner.fail("Failed to fetch problems");
899
1138
  if (error instanceof Error) {
900
- console.log(chalk4.red(error.message));
1139
+ console.log(chalk5.red(error.message));
901
1140
  }
902
1141
  }
903
1142
  }
904
1143
 
905
1144
  // src/commands/show.ts
906
1145
  import ora3 from "ora";
907
- import chalk5 from "chalk";
1146
+ import chalk6 from "chalk";
908
1147
  async function showCommand(idOrSlug) {
909
1148
  const { authorized } = await requireAuth();
910
1149
  if (!authorized) return;
@@ -925,68 +1164,227 @@ async function showCommand(idOrSlug) {
925
1164
  } catch (error) {
926
1165
  spinner.fail("Failed to fetch problem");
927
1166
  if (error instanceof Error) {
928
- console.log(chalk5.red(error.message));
1167
+ console.log(chalk6.red(error.message));
929
1168
  }
930
1169
  }
931
1170
  }
932
1171
 
933
1172
  // src/commands/pick.ts
934
1173
  import { writeFile, mkdir } from "fs/promises";
935
- import { existsSync } from "fs";
936
- import { join as join3 } from "path";
1174
+ import { existsSync as existsSync2 } from "fs";
1175
+ import { join as join4 } from "path";
937
1176
  import ora4 from "ora";
938
- import chalk7 from "chalk";
1177
+ import chalk8 from "chalk";
939
1178
 
940
1179
  // src/storage/config.ts
941
- import Conf2 from "conf";
942
- import { homedir as homedir2 } from "os";
1180
+ import { join as join3 } from "path";
1181
+
1182
+ // src/storage/workspaces.ts
1183
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
943
1184
  import { join as join2 } from "path";
944
- var configStore = new Conf2({
945
- configName: "config",
946
- cwd: join2(homedir2(), ".leetcode"),
947
- defaults: {
948
- language: "typescript",
949
- workDir: join2(homedir2(), "leetcode")
1185
+ import { homedir as homedir2 } from "os";
1186
+ var LEETCODE_DIR = join2(homedir2(), ".leetcode");
1187
+ var WORKSPACES_FILE = join2(LEETCODE_DIR, "workspaces.json");
1188
+ var WORKSPACES_DIR = join2(LEETCODE_DIR, "workspaces");
1189
+ function ensureDir(dir) {
1190
+ if (!existsSync(dir)) {
1191
+ mkdirSync(dir, { recursive: true });
950
1192
  }
951
- });
1193
+ }
1194
+ function loadRegistry() {
1195
+ if (existsSync(WORKSPACES_FILE)) {
1196
+ return JSON.parse(readFileSync(WORKSPACES_FILE, "utf-8"));
1197
+ }
1198
+ return { active: "default", workspaces: [] };
1199
+ }
1200
+ function saveRegistry(registry) {
1201
+ ensureDir(LEETCODE_DIR);
1202
+ writeFileSync(WORKSPACES_FILE, JSON.stringify(registry, null, 2));
1203
+ }
1204
+ var workspaceStorage = {
1205
+ /**
1206
+ * Initialize workspaces on first run - migrate existing config to "default" workspace
1207
+ */
1208
+ ensureInitialized() {
1209
+ const registry = loadRegistry();
1210
+ if (registry.workspaces.length === 0) {
1211
+ this.create("default", {
1212
+ workDir: join2(homedir2(), "leetcode"),
1213
+ lang: "typescript"
1214
+ });
1215
+ registry.workspaces = ["default"];
1216
+ registry.active = "default";
1217
+ saveRegistry(registry);
1218
+ }
1219
+ },
1220
+ /**
1221
+ * Get the currently active workspace name
1222
+ */
1223
+ getActive() {
1224
+ this.ensureInitialized();
1225
+ return loadRegistry().active;
1226
+ },
1227
+ /**
1228
+ * Set the active workspace
1229
+ */
1230
+ setActive(name) {
1231
+ const registry = loadRegistry();
1232
+ if (!registry.workspaces.includes(name)) {
1233
+ return false;
1234
+ }
1235
+ registry.active = name;
1236
+ saveRegistry(registry);
1237
+ return true;
1238
+ },
1239
+ /**
1240
+ * List all workspace names
1241
+ */
1242
+ list() {
1243
+ this.ensureInitialized();
1244
+ return loadRegistry().workspaces;
1245
+ },
1246
+ /**
1247
+ * Check if a workspace exists
1248
+ */
1249
+ exists(name) {
1250
+ this.ensureInitialized();
1251
+ return loadRegistry().workspaces.includes(name);
1252
+ },
1253
+ /**
1254
+ * Create a new workspace
1255
+ */
1256
+ create(name, config2) {
1257
+ const registry = loadRegistry();
1258
+ if (registry.workspaces.includes(name)) {
1259
+ return false;
1260
+ }
1261
+ const wsDir = join2(WORKSPACES_DIR, name);
1262
+ ensureDir(wsDir);
1263
+ ensureDir(join2(wsDir, "snapshots"));
1264
+ const configPath = join2(wsDir, "config.json");
1265
+ writeFileSync(configPath, JSON.stringify(config2, null, 2));
1266
+ writeFileSync(join2(wsDir, "timer.json"), JSON.stringify({ solveTimes: {}, activeTimer: null }, null, 2));
1267
+ writeFileSync(join2(wsDir, "collab.json"), JSON.stringify({ session: null }, null, 2));
1268
+ registry.workspaces.push(name);
1269
+ saveRegistry(registry);
1270
+ return true;
1271
+ },
1272
+ /**
1273
+ * Delete a workspace
1274
+ */
1275
+ delete(name) {
1276
+ if (name === "default") {
1277
+ return false;
1278
+ }
1279
+ const registry = loadRegistry();
1280
+ if (!registry.workspaces.includes(name)) {
1281
+ return false;
1282
+ }
1283
+ registry.workspaces = registry.workspaces.filter((w) => w !== name);
1284
+ if (registry.active === name) {
1285
+ registry.active = "default";
1286
+ }
1287
+ saveRegistry(registry);
1288
+ return true;
1289
+ },
1290
+ /**
1291
+ * Get the directory path for a workspace
1292
+ */
1293
+ getWorkspaceDir(name) {
1294
+ const wsName = name ?? this.getActive();
1295
+ return join2(WORKSPACES_DIR, wsName);
1296
+ },
1297
+ /**
1298
+ * Get config for a workspace
1299
+ */
1300
+ getConfig(name) {
1301
+ const wsName = name ?? this.getActive();
1302
+ const configPath = join2(WORKSPACES_DIR, wsName, "config.json");
1303
+ if (existsSync(configPath)) {
1304
+ return JSON.parse(readFileSync(configPath, "utf-8"));
1305
+ }
1306
+ return {
1307
+ workDir: join2(homedir2(), "leetcode"),
1308
+ lang: "typescript"
1309
+ };
1310
+ },
1311
+ /**
1312
+ * Update config for a workspace
1313
+ */
1314
+ setConfig(config2, name) {
1315
+ const wsName = name ?? this.getActive();
1316
+ const wsDir = join2(WORKSPACES_DIR, wsName);
1317
+ ensureDir(wsDir);
1318
+ const currentConfig = this.getConfig(wsName);
1319
+ const newConfig = { ...currentConfig, ...config2 };
1320
+ writeFileSync(join2(wsDir, "config.json"), JSON.stringify(newConfig, null, 2));
1321
+ },
1322
+ /**
1323
+ * Get snapshots directory for active workspace
1324
+ */
1325
+ getSnapshotsDir() {
1326
+ return join2(this.getWorkspaceDir(), "snapshots");
1327
+ },
1328
+ /**
1329
+ * Get timer file path for active workspace
1330
+ */
1331
+ getTimerPath() {
1332
+ return join2(this.getWorkspaceDir(), "timer.json");
1333
+ },
1334
+ /**
1335
+ * Get collab file path for active workspace
1336
+ */
1337
+ getCollabPath() {
1338
+ return join2(this.getWorkspaceDir(), "collab.json");
1339
+ }
1340
+ };
1341
+
1342
+ // src/storage/config.ts
952
1343
  var config = {
953
1344
  getConfig() {
1345
+ const wsConfig = workspaceStorage.getConfig();
954
1346
  return {
955
- language: configStore.get("language"),
956
- editor: configStore.get("editor"),
957
- workDir: configStore.get("workDir"),
958
- repo: configStore.get("repo")
1347
+ language: wsConfig.lang,
1348
+ editor: wsConfig.editor,
1349
+ workDir: wsConfig.workDir,
1350
+ repo: wsConfig.syncRepo
959
1351
  };
960
1352
  },
961
1353
  setLanguage(language) {
962
- configStore.set("language", language);
1354
+ workspaceStorage.setConfig({ lang: language });
963
1355
  },
964
1356
  setEditor(editor) {
965
- configStore.set("editor", editor);
1357
+ workspaceStorage.setConfig({ editor });
966
1358
  },
967
1359
  setWorkDir(workDir) {
968
- configStore.set("workDir", workDir);
1360
+ workspaceStorage.setConfig({ workDir });
969
1361
  },
970
1362
  setRepo(repo) {
971
- configStore.set("repo", repo);
1363
+ workspaceStorage.setConfig({ syncRepo: repo });
972
1364
  },
973
1365
  deleteRepo() {
974
- configStore.delete("repo");
1366
+ const wsConfig = workspaceStorage.getConfig();
1367
+ delete wsConfig.syncRepo;
1368
+ workspaceStorage.setConfig(wsConfig);
975
1369
  },
976
1370
  getLanguage() {
977
- return configStore.get("language");
1371
+ return workspaceStorage.getConfig().lang;
978
1372
  },
979
1373
  getEditor() {
980
- return configStore.get("editor");
1374
+ return workspaceStorage.getConfig().editor;
981
1375
  },
982
1376
  getWorkDir() {
983
- return configStore.get("workDir");
1377
+ return workspaceStorage.getConfig().workDir;
984
1378
  },
985
1379
  getRepo() {
986
- return configStore.get("repo");
1380
+ return workspaceStorage.getConfig().syncRepo;
987
1381
  },
988
1382
  getPath() {
989
- return configStore.path;
1383
+ return join3(workspaceStorage.getWorkspaceDir(), "config.json");
1384
+ },
1385
+ // New workspace-aware methods
1386
+ getActiveWorkspace() {
1387
+ return workspaceStorage.getActive();
990
1388
  }
991
1389
  };
992
1390
 
@@ -1112,7 +1510,7 @@ function getSolutionFileName(problemId, titleSlug, language) {
1112
1510
  // src/utils/editor.ts
1113
1511
  import { spawn } from "child_process";
1114
1512
  import open from "open";
1115
- import chalk6 from "chalk";
1513
+ import chalk7 from "chalk";
1116
1514
  var TERMINAL_EDITORS = ["vim", "nvim", "vi", "nano", "emacs", "micro", "helix"];
1117
1515
  var VSCODE_EDITORS = ["code", "code-insiders", "cursor", "codium", "vscodium"];
1118
1516
  async function openInEditor(filePath, workDir) {
@@ -1120,7 +1518,7 @@ async function openInEditor(filePath, workDir) {
1120
1518
  const workspace = workDir ?? config.getWorkDir();
1121
1519
  if (TERMINAL_EDITORS.includes(editor)) {
1122
1520
  console.log();
1123
- console.log(chalk6.gray(`Open with: ${editor} ${filePath}`));
1521
+ console.log(chalk7.gray(`Open with: ${editor} ${filePath}`));
1124
1522
  return;
1125
1523
  }
1126
1524
  try {
@@ -1160,13 +1558,13 @@ async function pickCommand(idOrSlug, options) {
1160
1558
  const template = getCodeTemplate(snippets, language);
1161
1559
  let code;
1162
1560
  if (snippets.length === 0) {
1163
- spinner.warn(chalk7.yellow("Premium Problem (No code snippets available)"));
1164
- console.log(chalk7.gray("Generating placeholder file with problem info..."));
1561
+ spinner.warn(chalk8.yellow("Premium Problem (No code snippets available)"));
1562
+ console.log(chalk8.gray("Generating placeholder file with problem info..."));
1165
1563
  code = `// \u{1F512} Premium Problem - ${problem.title}
1166
1564
  // Solution stub not available - visit LeetCode to view`;
1167
1565
  } else if (!template) {
1168
1566
  spinner.fail(`No code template available for ${language}`);
1169
- console.log(chalk7.gray(`Available languages: ${snippets.map((s) => s.langSlug).join(", ")}`));
1567
+ console.log(chalk8.gray(`Available languages: ${snippets.map((s) => s.langSlug).join(", ")}`));
1170
1568
  return false;
1171
1569
  } else {
1172
1570
  code = template.code;
@@ -1183,26 +1581,26 @@ async function pickCommand(idOrSlug, options) {
1183
1581
  const workDir = config.getWorkDir();
1184
1582
  const difficulty = problem.difficulty;
1185
1583
  const category = problem.topicTags.length > 0 ? problem.topicTags[0].name.replace(/[^\w\s-]/g, "").trim() : "Uncategorized";
1186
- const targetDir = join3(workDir, difficulty, category);
1187
- if (!existsSync(targetDir)) {
1584
+ const targetDir = join4(workDir, difficulty, category);
1585
+ if (!existsSync2(targetDir)) {
1188
1586
  await mkdir(targetDir, { recursive: true });
1189
1587
  }
1190
1588
  const fileName = getSolutionFileName(problem.questionFrontendId, problem.titleSlug, language);
1191
- const filePath = join3(targetDir, fileName);
1192
- if (existsSync(filePath)) {
1589
+ const filePath = join4(targetDir, fileName);
1590
+ if (existsSync2(filePath)) {
1193
1591
  spinner.warn(`File already exists: ${fileName}`);
1194
- console.log(chalk7.gray(`Path: ${filePath}`));
1592
+ console.log(chalk8.gray(`Path: ${filePath}`));
1195
1593
  if (options.open !== false) {
1196
1594
  await openInEditor(filePath);
1197
1595
  }
1198
1596
  return true;
1199
1597
  }
1200
1598
  await writeFile(filePath, content, "utf-8");
1201
- spinner.succeed(`Created ${chalk7.green(fileName)}`);
1202
- console.log(chalk7.gray(`Path: ${filePath}`));
1599
+ spinner.succeed(`Created ${chalk8.green(fileName)}`);
1600
+ console.log(chalk8.gray(`Path: ${filePath}`));
1203
1601
  console.log();
1204
- console.log(chalk7.cyan(`${problem.questionFrontendId}. ${problem.title}`));
1205
- console.log(chalk7.gray(`Difficulty: ${problem.difficulty} | Category: ${category}`));
1602
+ console.log(chalk8.cyan(`${problem.questionFrontendId}. ${problem.title}`));
1603
+ console.log(chalk8.gray(`Difficulty: ${problem.difficulty} | Category: ${category}`));
1206
1604
  if (options.open !== false) {
1207
1605
  await openInEditor(filePath);
1208
1606
  }
@@ -1211,17 +1609,17 @@ async function pickCommand(idOrSlug, options) {
1211
1609
  spinner.fail("Failed to fetch problem");
1212
1610
  if (error instanceof Error) {
1213
1611
  if (error.message.includes("expected object, received null")) {
1214
- console.log(chalk7.red(`Problem "${idOrSlug}" not found`));
1612
+ console.log(chalk8.red(`Problem "${idOrSlug}" not found`));
1215
1613
  } else {
1216
1614
  try {
1217
1615
  const zodError = JSON.parse(error.message);
1218
1616
  if (Array.isArray(zodError)) {
1219
- console.log(chalk7.red("API Response Validation Failed"));
1617
+ console.log(chalk8.red("API Response Validation Failed"));
1220
1618
  } else {
1221
- console.log(chalk7.red(error.message));
1619
+ console.log(chalk8.red(error.message));
1222
1620
  }
1223
1621
  } catch {
1224
- console.log(chalk7.red(error.message));
1622
+ console.log(chalk8.red(error.message));
1225
1623
  }
1226
1624
  }
1227
1625
  }
@@ -1230,12 +1628,12 @@ async function pickCommand(idOrSlug, options) {
1230
1628
  }
1231
1629
  async function batchPickCommand(ids, options) {
1232
1630
  if (ids.length === 0) {
1233
- console.log(chalk7.yellow("Please provide at least one problem ID"));
1631
+ console.log(chalk8.yellow("Please provide at least one problem ID"));
1234
1632
  return;
1235
1633
  }
1236
1634
  const { authorized } = await requireAuth();
1237
1635
  if (!authorized) return;
1238
- console.log(chalk7.cyan(`\u{1F4E6} Picking ${ids.length} problem${ids.length !== 1 ? "s" : ""}...`));
1636
+ console.log(chalk8.cyan(`\u{1F4E6} Picking ${ids.length} problem${ids.length !== 1 ? "s" : ""}...`));
1239
1637
  console.log();
1240
1638
  console.log();
1241
1639
  let succeeded = 0;
@@ -1249,33 +1647,33 @@ async function batchPickCommand(ids, options) {
1249
1647
  }
1250
1648
  console.log();
1251
1649
  }
1252
- console.log(chalk7.gray("\u2500".repeat(50)));
1650
+ console.log(chalk8.gray("\u2500".repeat(50)));
1253
1651
  console.log(
1254
- chalk7.bold(
1255
- `Done! ${chalk7.green(`${succeeded} succeeded`)}${failed > 0 ? `, ${chalk7.red(`${failed} failed`)}` : ""}`
1652
+ chalk8.bold(
1653
+ `Done! ${chalk8.green(`${succeeded} succeeded`)}${failed > 0 ? `, ${chalk8.red(`${failed} failed`)}` : ""}`
1256
1654
  )
1257
1655
  );
1258
1656
  }
1259
1657
 
1260
1658
  // src/commands/test.ts
1261
1659
  import { readFile } from "fs/promises";
1262
- import { existsSync as existsSync3 } from "fs";
1660
+ import { existsSync as existsSync4 } from "fs";
1263
1661
  import { basename } from "path";
1264
1662
  import ora5 from "ora";
1265
- import chalk8 from "chalk";
1663
+ import chalk9 from "chalk";
1266
1664
 
1267
1665
  // src/utils/fileUtils.ts
1268
1666
  import { readdir } from "fs/promises";
1269
- import { existsSync as existsSync2 } from "fs";
1270
- import { join as join4 } from "path";
1667
+ import { existsSync as existsSync3 } from "fs";
1668
+ import { join as join5 } from "path";
1271
1669
  var MAX_SEARCH_DEPTH = 5;
1272
1670
  async function findSolutionFile(dir, problemId, currentDepth = 0) {
1273
- if (!existsSync2(dir)) return null;
1671
+ if (!existsSync3(dir)) return null;
1274
1672
  if (currentDepth >= MAX_SEARCH_DEPTH) return null;
1275
1673
  const entries = await readdir(dir, { withFileTypes: true });
1276
1674
  for (const entry of entries) {
1277
1675
  if (entry.name.startsWith(".")) continue;
1278
- const fullPath = join4(dir, entry.name);
1676
+ const fullPath = join5(dir, entry.name);
1279
1677
  if (entry.isDirectory()) {
1280
1678
  const found = await findSolutionFile(fullPath, problemId, currentDepth + 1);
1281
1679
  if (found) return found;
@@ -1289,11 +1687,11 @@ async function findSolutionFile(dir, problemId, currentDepth = 0) {
1289
1687
  return null;
1290
1688
  }
1291
1689
  async function findFileByName(dir, fileName, currentDepth = 0) {
1292
- if (!existsSync2(dir)) return null;
1690
+ if (!existsSync3(dir)) return null;
1293
1691
  if (currentDepth >= MAX_SEARCH_DEPTH) return null;
1294
1692
  const entries = await readdir(dir, { withFileTypes: true });
1295
1693
  for (const entry of entries) {
1296
- const fullPath = join4(dir, entry.name);
1694
+ const fullPath = join5(dir, entry.name);
1297
1695
  if (entry.isDirectory()) {
1298
1696
  const found = await findFileByName(fullPath, fileName, currentDepth + 1);
1299
1697
  if (found) return found;
@@ -1350,26 +1748,26 @@ async function testCommand(fileOrId, options) {
1350
1748
  const workDir = config.getWorkDir();
1351
1749
  const found = await findSolutionFile(workDir, fileOrId);
1352
1750
  if (!found) {
1353
- console.log(chalk8.red(`No solution file found for problem ${fileOrId}`));
1354
- console.log(chalk8.gray(`Looking in: ${workDir}`));
1355
- console.log(chalk8.gray(`Run "leetcode pick ${fileOrId}" first to create a solution file.`));
1751
+ console.log(chalk9.red(`No solution file found for problem ${fileOrId}`));
1752
+ console.log(chalk9.gray(`Looking in: ${workDir}`));
1753
+ console.log(chalk9.gray(`Run "leetcode pick ${fileOrId}" first to create a solution file.`));
1356
1754
  return;
1357
1755
  }
1358
1756
  filePath = found;
1359
- console.log(chalk8.gray(`Found: ${filePath}`));
1757
+ console.log(chalk9.gray(`Found: ${filePath}`));
1360
1758
  } else if (isFileName(fileOrId)) {
1361
1759
  const workDir = config.getWorkDir();
1362
1760
  const found = await findFileByName(workDir, fileOrId);
1363
1761
  if (!found) {
1364
- console.log(chalk8.red(`File not found: ${fileOrId}`));
1365
- console.log(chalk8.gray(`Looking in: ${workDir}`));
1762
+ console.log(chalk9.red(`File not found: ${fileOrId}`));
1763
+ console.log(chalk9.gray(`Looking in: ${workDir}`));
1366
1764
  return;
1367
1765
  }
1368
1766
  filePath = found;
1369
- console.log(chalk8.gray(`Found: ${filePath}`));
1767
+ console.log(chalk9.gray(`Found: ${filePath}`));
1370
1768
  }
1371
- if (!existsSync3(filePath)) {
1372
- console.log(chalk8.red(`File not found: ${filePath}`));
1769
+ if (!existsSync4(filePath)) {
1770
+ console.log(chalk9.red(`File not found: ${filePath}`));
1373
1771
  return;
1374
1772
  }
1375
1773
  const spinner = ora5({ text: "Reading solution file...", spinner: "dots" }).start();
@@ -1378,8 +1776,8 @@ async function testCommand(fileOrId, options) {
1378
1776
  const match = fileName.match(/^(\d+)\.([^.]+)\./);
1379
1777
  if (!match) {
1380
1778
  spinner.fail("Invalid filename format");
1381
- console.log(chalk8.gray("Expected format: {id}.{title-slug}.{ext}"));
1382
- console.log(chalk8.gray("Example: 1.two-sum.ts"));
1779
+ console.log(chalk9.gray("Expected format: {id}.{title-slug}.{ext}"));
1780
+ console.log(chalk9.gray("Example: 1.two-sum.ts"));
1383
1781
  return;
1384
1782
  }
1385
1783
  const [, problemId, titleSlug] = match;
@@ -1396,62 +1794,75 @@ async function testCommand(fileOrId, options) {
1396
1794
  spinner.text = "Running tests...";
1397
1795
  const result = await leetcodeClient.testSolution(titleSlug, code, lang, testcases, problem.questionId);
1398
1796
  spinner.stop();
1399
- displayTestResult(result);
1797
+ displayTestResult(result, options.visualize ? problem.topicTags : void 0);
1400
1798
  } catch (error) {
1401
1799
  spinner.fail("Test failed");
1402
1800
  if (error instanceof Error) {
1403
- console.log(chalk8.red(error.message));
1801
+ console.log(chalk9.red(error.message));
1404
1802
  }
1405
1803
  }
1406
1804
  }
1407
1805
 
1408
1806
  // src/commands/submit.ts
1409
1807
  import { readFile as readFile2 } from "fs/promises";
1410
- import { existsSync as existsSync4 } from "fs";
1808
+ import { existsSync as existsSync6 } from "fs";
1411
1809
  import { basename as basename2 } from "path";
1412
1810
  import ora6 from "ora";
1413
- import chalk9 from "chalk";
1811
+ import chalk10 from "chalk";
1414
1812
 
1415
1813
  // src/storage/timer.ts
1416
- import Conf3 from "conf";
1417
- import { homedir as homedir3 } from "os";
1418
- import { join as join5 } from "path";
1419
- var timerStore = new Conf3({
1420
- configName: "timer",
1421
- cwd: join5(homedir3(), ".leetcode"),
1422
- defaults: {
1423
- solveTimes: {},
1424
- activeTimer: null
1814
+ import { existsSync as existsSync5, readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
1815
+ import { dirname } from "path";
1816
+ function getTimerPath() {
1817
+ return workspaceStorage.getTimerPath();
1818
+ }
1819
+ function loadTimer() {
1820
+ const path = getTimerPath();
1821
+ if (existsSync5(path)) {
1822
+ return JSON.parse(readFileSync2(path, "utf-8"));
1425
1823
  }
1426
- });
1824
+ return { solveTimes: {}, activeTimer: null };
1825
+ }
1826
+ function saveTimer(data) {
1827
+ const timerPath = getTimerPath();
1828
+ const dir = dirname(timerPath);
1829
+ if (!existsSync5(dir)) {
1830
+ mkdirSync2(dir, { recursive: true });
1831
+ }
1832
+ writeFileSync2(timerPath, JSON.stringify(data, null, 2));
1833
+ }
1427
1834
  var timerStorage = {
1428
1835
  startTimer(problemId, title, difficulty, durationMinutes) {
1429
- timerStore.set("activeTimer", {
1836
+ const data = loadTimer();
1837
+ data.activeTimer = {
1430
1838
  problemId,
1431
1839
  title,
1432
1840
  difficulty,
1433
1841
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
1434
1842
  durationMinutes
1435
- });
1843
+ };
1844
+ saveTimer(data);
1436
1845
  },
1437
1846
  getActiveTimer() {
1438
- return timerStore.get("activeTimer");
1847
+ return loadTimer().activeTimer;
1439
1848
  },
1440
1849
  stopTimer() {
1441
- const active = timerStore.get("activeTimer");
1850
+ const data = loadTimer();
1851
+ const active = data.activeTimer;
1442
1852
  if (!active) return null;
1443
1853
  const startedAt = new Date(active.startedAt);
1444
1854
  const now = /* @__PURE__ */ new Date();
1445
1855
  const durationSeconds = Math.floor((now.getTime() - startedAt.getTime()) / 1e3);
1446
- timerStore.set("activeTimer", null);
1856
+ data.activeTimer = null;
1857
+ saveTimer(data);
1447
1858
  return { durationSeconds };
1448
1859
  },
1449
1860
  recordSolveTime(problemId, title, difficulty, durationSeconds, timerMinutes) {
1450
- const solveTimes = timerStore.get("solveTimes") ?? {};
1451
- if (!solveTimes[problemId]) {
1452
- solveTimes[problemId] = [];
1861
+ const data = loadTimer();
1862
+ if (!data.solveTimes[problemId]) {
1863
+ data.solveTimes[problemId] = [];
1453
1864
  }
1454
- solveTimes[problemId].push({
1865
+ data.solveTimes[problemId].push({
1455
1866
  problemId,
1456
1867
  title,
1457
1868
  difficulty,
@@ -1459,17 +1870,17 @@ var timerStorage = {
1459
1870
  durationSeconds,
1460
1871
  timerMinutes
1461
1872
  });
1462
- timerStore.set("solveTimes", solveTimes);
1873
+ saveTimer(data);
1463
1874
  },
1464
1875
  getSolveTimes(problemId) {
1465
- const solveTimes = timerStore.get("solveTimes") ?? {};
1466
- return solveTimes[problemId] ?? [];
1876
+ const data = loadTimer();
1877
+ return data.solveTimes[problemId] ?? [];
1467
1878
  },
1468
1879
  getAllSolveTimes() {
1469
- return timerStore.get("solveTimes") ?? {};
1880
+ return loadTimer().solveTimes ?? {};
1470
1881
  },
1471
1882
  getStats() {
1472
- const solveTimes = timerStore.get("solveTimes") ?? {};
1883
+ const solveTimes = loadTimer().solveTimes ?? {};
1473
1884
  let totalProblems = 0;
1474
1885
  let totalTime = 0;
1475
1886
  for (const times of Object.values(solveTimes)) {
@@ -1495,26 +1906,26 @@ async function submitCommand(fileOrId) {
1495
1906
  const workDir = config.getWorkDir();
1496
1907
  const found = await findSolutionFile(workDir, fileOrId);
1497
1908
  if (!found) {
1498
- console.log(chalk9.red(`No solution file found for problem ${fileOrId}`));
1499
- console.log(chalk9.gray(`Looking in: ${workDir}`));
1500
- console.log(chalk9.gray(`Run "leetcode pick ${fileOrId}" first to create a solution file.`));
1909
+ console.log(chalk10.red(`No solution file found for problem ${fileOrId}`));
1910
+ console.log(chalk10.gray(`Looking in: ${workDir}`));
1911
+ console.log(chalk10.gray(`Run "leetcode pick ${fileOrId}" first to create a solution file.`));
1501
1912
  return;
1502
1913
  }
1503
1914
  filePath = found;
1504
- console.log(chalk9.gray(`Found: ${filePath}`));
1915
+ console.log(chalk10.gray(`Found: ${filePath}`));
1505
1916
  } else if (isFileName(fileOrId)) {
1506
1917
  const workDir = config.getWorkDir();
1507
1918
  const found = await findFileByName(workDir, fileOrId);
1508
1919
  if (!found) {
1509
- console.log(chalk9.red(`File not found: ${fileOrId}`));
1510
- console.log(chalk9.gray(`Looking in: ${workDir}`));
1920
+ console.log(chalk10.red(`File not found: ${fileOrId}`));
1921
+ console.log(chalk10.gray(`Looking in: ${workDir}`));
1511
1922
  return;
1512
1923
  }
1513
1924
  filePath = found;
1514
- console.log(chalk9.gray(`Found: ${filePath}`));
1925
+ console.log(chalk10.gray(`Found: ${filePath}`));
1515
1926
  }
1516
- if (!existsSync4(filePath)) {
1517
- console.log(chalk9.red(`File not found: ${filePath}`));
1927
+ if (!existsSync6(filePath)) {
1928
+ console.log(chalk10.red(`File not found: ${filePath}`));
1518
1929
  return;
1519
1930
  }
1520
1931
  const spinner = ora6({ text: "Reading solution file...", spinner: "dots" }).start();
@@ -1523,8 +1934,8 @@ async function submitCommand(fileOrId) {
1523
1934
  const match = fileName.match(/^(\d+)\.([^.]+)\./);
1524
1935
  if (!match) {
1525
1936
  spinner.fail("Invalid filename format");
1526
- console.log(chalk9.gray("Expected format: {id}.{title-slug}.{ext}"));
1527
- console.log(chalk9.gray("Example: 1.two-sum.ts"));
1937
+ console.log(chalk10.gray("Expected format: {id}.{title-slug}.{ext}"));
1938
+ console.log(chalk10.gray("Example: 1.two-sum.ts"));
1528
1939
  return;
1529
1940
  }
1530
1941
  const [, problemId, titleSlug] = match;
@@ -1563,14 +1974,14 @@ async function submitCommand(fileOrId) {
1563
1974
  const timeStr = `${mins}m ${secs}s`;
1564
1975
  const withinLimit = timerResult.durationSeconds <= activeTimer.durationMinutes * 60;
1565
1976
  console.log();
1566
- console.log(chalk9.bold("\u23F1\uFE0F Timer Result:"));
1977
+ console.log(chalk10.bold("\u23F1\uFE0F Timer Result:"));
1567
1978
  console.log(
1568
- ` Solved in ${withinLimit ? chalk9.green(timeStr) : chalk9.yellow(timeStr)} (limit: ${activeTimer.durationMinutes}m)`
1979
+ ` Solved in ${withinLimit ? chalk10.green(timeStr) : chalk10.yellow(timeStr)} (limit: ${activeTimer.durationMinutes}m)`
1569
1980
  );
1570
1981
  if (withinLimit) {
1571
- console.log(chalk9.green(" \u2713 Within time limit!"));
1982
+ console.log(chalk10.green(" \u2713 Within time limit!"));
1572
1983
  } else {
1573
- console.log(chalk9.yellow(" \u26A0 Exceeded time limit"));
1984
+ console.log(chalk10.yellow(" \u26A0 Exceeded time limit"));
1574
1985
  }
1575
1986
  }
1576
1987
  }
@@ -1578,17 +1989,17 @@ async function submitCommand(fileOrId) {
1578
1989
  } catch (error) {
1579
1990
  spinner.fail("Submission failed");
1580
1991
  if (error instanceof Error) {
1581
- console.log(chalk9.red(error.message));
1992
+ console.log(chalk10.red(error.message));
1582
1993
  }
1583
1994
  }
1584
1995
  }
1585
1996
 
1586
1997
  // src/commands/stat.ts
1587
1998
  import ora7 from "ora";
1588
- import chalk11 from "chalk";
1999
+ import chalk12 from "chalk";
1589
2000
 
1590
2001
  // src/utils/stats-display.ts
1591
- import chalk10 from "chalk";
2002
+ import chalk11 from "chalk";
1592
2003
  var MONTH_NAMES = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
1593
2004
  function renderHeatmap(calendarJson) {
1594
2005
  const data = JSON.parse(calendarJson);
@@ -1621,25 +2032,25 @@ function renderHeatmap(calendarJson) {
1621
2032
  const totalSubmissions = weeks.reduce((sum, w) => sum + w.count, 0);
1622
2033
  const totalActiveDays = weeks.reduce((sum, w) => sum + w.days, 0);
1623
2034
  console.log();
1624
- console.log(chalk10.bold("\u{1F4C5} Activity (Last 12 Weeks)"));
1625
- console.log(chalk10.gray("How many problems you submitted and days you practiced."));
1626
- console.log(chalk10.gray("\u2500".repeat(50)));
2035
+ console.log(chalk11.bold("\u{1F4C5} Activity (Last 12 Weeks)"));
2036
+ console.log(chalk11.gray("How many problems you submitted and days you practiced."));
2037
+ console.log(chalk11.gray("\u2500".repeat(50)));
1627
2038
  console.log();
1628
2039
  for (const week of weeks) {
1629
2040
  const weekLabel = `${week.start} - ${week.end}`.padEnd(18);
1630
- const bar = week.count > 0 ? chalk10.green("\u2588".repeat(Math.min(week.count, 10))).padEnd(10) : chalk10.gray("\xB7").padEnd(10);
2041
+ const bar = week.count > 0 ? chalk11.green("\u2588".repeat(Math.min(week.count, 10))).padEnd(10) : chalk11.gray("\xB7").padEnd(10);
1631
2042
  const countStr = week.count > 0 ? `${week.count} subs`.padEnd(10) : "".padEnd(10);
1632
2043
  const daysStr = week.days > 0 ? `${week.days}d active` : "";
1633
- console.log(` ${chalk10.white(weekLabel)} ${bar} ${chalk10.cyan(countStr)} ${chalk10.yellow(daysStr)}`);
2044
+ console.log(` ${chalk11.white(weekLabel)} ${bar} ${chalk11.cyan(countStr)} ${chalk11.yellow(daysStr)}`);
1634
2045
  }
1635
- console.log(chalk10.gray("\u2500".repeat(50)));
1636
- console.log(` ${chalk10.bold.white("Total:")} ${chalk10.cyan.bold(totalSubmissions + " submissions")}, ${chalk10.yellow.bold(totalActiveDays + " days active")}`);
2046
+ console.log(chalk11.gray("\u2500".repeat(50)));
2047
+ console.log(` ${chalk11.bold.white("Total:")} ${chalk11.cyan.bold(totalSubmissions + " submissions")}, ${chalk11.yellow.bold(totalActiveDays + " days active")}`);
1637
2048
  console.log();
1638
2049
  }
1639
2050
  function renderSkillStats(fundamental, intermediate, advanced) {
1640
2051
  console.log();
1641
- console.log(chalk10.bold("\u{1F3AF} Skill Breakdown"));
1642
- console.log(chalk10.gray("\u2500".repeat(45)));
2052
+ console.log(chalk11.bold("\u{1F3AF} Skill Breakdown"));
2053
+ console.log(chalk11.gray("\u2500".repeat(45)));
1643
2054
  const renderSection = (title, stats, color) => {
1644
2055
  if (stats.length === 0) return;
1645
2056
  console.log();
@@ -1648,12 +2059,12 @@ function renderSkillStats(fundamental, intermediate, advanced) {
1648
2059
  for (const stat of sorted.slice(0, 8)) {
1649
2060
  const name = stat.tagName.padEnd(22);
1650
2061
  const bar = color("\u2588".repeat(Math.min(stat.problemsSolved, 15)));
1651
- console.log(` ${chalk10.white(name)} ${bar} ${chalk10.white(stat.problemsSolved)}`);
2062
+ console.log(` ${chalk11.white(name)} ${bar} ${chalk11.white(stat.problemsSolved)}`);
1652
2063
  }
1653
2064
  };
1654
- renderSection("Fundamental", fundamental, chalk10.green);
1655
- renderSection("Intermediate", intermediate, chalk10.yellow);
1656
- renderSection("Advanced", advanced, chalk10.red);
2065
+ renderSection("Fundamental", fundamental, chalk11.green);
2066
+ renderSection("Intermediate", intermediate, chalk11.yellow);
2067
+ renderSection("Advanced", advanced, chalk11.red);
1657
2068
  console.log();
1658
2069
  }
1659
2070
  function renderTrendChart(calendarJson) {
@@ -1674,15 +2085,15 @@ function renderTrendChart(calendarJson) {
1674
2085
  const maxVal = Math.max(...days.map((d) => d.count), 1);
1675
2086
  const chartHeight = 6;
1676
2087
  console.log();
1677
- console.log(chalk10.bold("\u{1F4C8} Submission Trend (Last 7 Days)"));
1678
- console.log(chalk10.gray("\u2500".repeat(35)));
2088
+ console.log(chalk11.bold("\u{1F4C8} Submission Trend (Last 7 Days)"));
2089
+ console.log(chalk11.gray("\u2500".repeat(35)));
1679
2090
  console.log();
1680
2091
  for (let row = chartHeight; row >= 1; row--) {
1681
2092
  let line = ` ${row === chartHeight ? maxVal.toString().padStart(2) : " "} \u2502`;
1682
2093
  for (const day of days) {
1683
2094
  const barHeight = Math.round(day.count / maxVal * chartHeight);
1684
2095
  if (barHeight >= row) {
1685
- line += chalk10.green(" \u2588\u2588 ");
2096
+ line += chalk11.green(" \u2588\u2588 ");
1686
2097
  } else {
1687
2098
  line += " ";
1688
2099
  }
@@ -1691,10 +2102,10 @@ function renderTrendChart(calendarJson) {
1691
2102
  }
1692
2103
  console.log(` 0 \u2514${"\u2500\u2500\u2500\u2500".repeat(7)}`);
1693
2104
  console.log(` ${days.map((d) => d.label.padEnd(4)).join("")}`);
1694
- console.log(chalk10.gray(` ${days.map((d) => d.count.toString().padEnd(4)).join("")}`));
2105
+ console.log(chalk11.gray(` ${days.map((d) => d.count.toString().padEnd(4)).join("")}`));
1695
2106
  const total = days.reduce((a, b) => a + b.count, 0);
1696
2107
  console.log();
1697
- console.log(chalk10.white(` Total: ${total} submissions this week`));
2108
+ console.log(chalk11.white(` Total: ${total} submissions this week`));
1698
2109
  console.log();
1699
2110
  }
1700
2111
 
@@ -1726,14 +2137,14 @@ async function statCommand(username, options = {}) {
1726
2137
  if (profile.submissionCalendar) {
1727
2138
  renderHeatmap(profile.submissionCalendar);
1728
2139
  } else {
1729
- console.log(chalk11.yellow("Calendar data not available."));
2140
+ console.log(chalk12.yellow("Calendar data not available."));
1730
2141
  }
1731
2142
  }
1732
2143
  if (options.trend) {
1733
2144
  if (profile.submissionCalendar) {
1734
2145
  renderTrendChart(profile.submissionCalendar);
1735
2146
  } else {
1736
- console.log(chalk11.yellow("Calendar data not available."));
2147
+ console.log(chalk12.yellow("Calendar data not available."));
1737
2148
  }
1738
2149
  }
1739
2150
  if (options.skills) {
@@ -1745,14 +2156,14 @@ async function statCommand(username, options = {}) {
1745
2156
  } catch (error) {
1746
2157
  spinner.fail("Failed to fetch statistics");
1747
2158
  if (error instanceof Error) {
1748
- console.log(chalk11.red(error.message));
2159
+ console.log(chalk12.red(error.message));
1749
2160
  }
1750
2161
  }
1751
2162
  }
1752
2163
 
1753
2164
  // src/commands/daily.ts
1754
2165
  import ora8 from "ora";
1755
- import chalk12 from "chalk";
2166
+ import chalk13 from "chalk";
1756
2167
  async function dailyCommand() {
1757
2168
  const { authorized } = await requireAuth();
1758
2169
  if (!authorized) return;
@@ -1762,19 +2173,19 @@ async function dailyCommand() {
1762
2173
  spinner.stop();
1763
2174
  displayDailyChallenge(daily.date, daily.question);
1764
2175
  console.log();
1765
- console.log(chalk12.gray("Run the following to start working on this problem:"));
1766
- console.log(chalk12.cyan(` leetcode pick ${daily.question.titleSlug}`));
2176
+ console.log(chalk13.gray("Run the following to start working on this problem:"));
2177
+ console.log(chalk13.cyan(` leetcode pick ${daily.question.titleSlug}`));
1767
2178
  } catch (error) {
1768
2179
  spinner.fail("Failed to fetch daily challenge");
1769
2180
  if (error instanceof Error) {
1770
- console.log(chalk12.red(error.message));
2181
+ console.log(chalk13.red(error.message));
1771
2182
  }
1772
2183
  }
1773
2184
  }
1774
2185
 
1775
2186
  // src/commands/random.ts
1776
2187
  import ora9 from "ora";
1777
- import chalk13 from "chalk";
2188
+ import chalk14 from "chalk";
1778
2189
  async function randomCommand(options) {
1779
2190
  const { authorized } = await requireAuth();
1780
2191
  if (!authorized) return;
@@ -1808,23 +2219,23 @@ async function randomCommand(options) {
1808
2219
  await pickCommand(titleSlug, { open: options.open ?? true });
1809
2220
  } else {
1810
2221
  await showCommand(titleSlug);
1811
- console.log(chalk13.gray("Run following to start solving:"));
1812
- console.log(chalk13.cyan(` leetcode pick ${titleSlug}`));
2222
+ console.log(chalk14.gray("Run following to start solving:"));
2223
+ console.log(chalk14.cyan(` leetcode pick ${titleSlug}`));
1813
2224
  }
1814
2225
  } catch (error) {
1815
2226
  spinner.fail("Failed to fetch random problem");
1816
2227
  if (error instanceof Error) {
1817
- console.log(chalk13.red(error.message));
2228
+ console.log(chalk14.red(error.message));
1818
2229
  }
1819
2230
  }
1820
2231
  }
1821
2232
 
1822
2233
  // src/commands/submissions.ts
1823
2234
  import { writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
1824
- import { existsSync as existsSync5 } from "fs";
2235
+ import { existsSync as existsSync7 } from "fs";
1825
2236
  import { join as join6 } from "path";
1826
2237
  import ora10 from "ora";
1827
- import chalk14 from "chalk";
2238
+ import chalk15 from "chalk";
1828
2239
  async function submissionsCommand(idOrSlug, options) {
1829
2240
  const { authorized } = await requireAuth();
1830
2241
  if (!authorized) return;
@@ -1846,16 +2257,16 @@ async function submissionsCommand(idOrSlug, options) {
1846
2257
  const submissions = await leetcodeClient.getSubmissionList(slug, limit);
1847
2258
  spinner.stop();
1848
2259
  if (submissions.length === 0) {
1849
- console.log(chalk14.yellow("No submissions found."));
2260
+ console.log(chalk15.yellow("No submissions found."));
1850
2261
  return;
1851
2262
  }
1852
2263
  if (options.last) {
1853
2264
  const lastAC = submissions.find((s) => s.statusDisplay === "Accepted");
1854
2265
  if (lastAC) {
1855
- console.log(chalk14.bold("Last Accepted Submission:"));
2266
+ console.log(chalk15.bold("Last Accepted Submission:"));
1856
2267
  displaySubmissionsList([lastAC]);
1857
2268
  } else {
1858
- console.log(chalk14.yellow("No accepted submissions found in recent history."));
2269
+ console.log(chalk15.yellow("No accepted submissions found in recent history."));
1859
2270
  }
1860
2271
  } else {
1861
2272
  displaySubmissionsList(submissions);
@@ -1877,7 +2288,7 @@ async function submissionsCommand(idOrSlug, options) {
1877
2288
  const difficulty = problem.difficulty;
1878
2289
  const category = problem.topicTags.length > 0 ? problem.topicTags[0].name.replace(/[^\w\s-]/g, "").trim() : "Uncategorized";
1879
2290
  const targetDir = join6(workDir, difficulty, category);
1880
- if (!existsSync5(targetDir)) {
2291
+ if (!existsSync7(targetDir)) {
1881
2292
  await mkdir2(targetDir, { recursive: true });
1882
2293
  }
1883
2294
  const langSlug = details.lang.name;
@@ -1886,20 +2297,20 @@ async function submissionsCommand(idOrSlug, options) {
1886
2297
  const fileName = `${problem.questionFrontendId}.${problem.titleSlug}.submission-${lastAC.id}.${ext}`;
1887
2298
  const filePath = join6(targetDir, fileName);
1888
2299
  await writeFile2(filePath, details.code, "utf-8");
1889
- downloadSpinner.succeed(`Downloaded to ${chalk14.green(fileName)}`);
1890
- console.log(chalk14.gray(`Path: ${filePath}`));
2300
+ downloadSpinner.succeed(`Downloaded to ${chalk15.green(fileName)}`);
2301
+ console.log(chalk15.gray(`Path: ${filePath}`));
1891
2302
  }
1892
2303
  } catch (error) {
1893
2304
  spinner.fail("Failed to fetch submissions");
1894
2305
  if (error instanceof Error) {
1895
- console.log(chalk14.red(error.message));
2306
+ console.log(chalk15.red(error.message));
1896
2307
  }
1897
2308
  }
1898
2309
  }
1899
2310
 
1900
2311
  // src/commands/config.ts
1901
2312
  import inquirer2 from "inquirer";
1902
- import chalk15 from "chalk";
2313
+ import chalk16 from "chalk";
1903
2314
  var SUPPORTED_LANGUAGES = [
1904
2315
  "typescript",
1905
2316
  "javascript",
@@ -1921,34 +2332,38 @@ async function configCommand(options) {
1921
2332
  if (options.lang) {
1922
2333
  const langInput = options.lang.toLowerCase();
1923
2334
  if (!SUPPORTED_LANGUAGES.includes(langInput)) {
1924
- console.log(chalk15.red(`Unsupported language: ${options.lang}`));
1925
- console.log(chalk15.gray(`Supported: ${SUPPORTED_LANGUAGES.join(", ")}`));
2335
+ console.log(chalk16.red(`Unsupported language: ${options.lang}`));
2336
+ console.log(chalk16.gray(`Supported: ${SUPPORTED_LANGUAGES.join(", ")}`));
1926
2337
  return;
1927
2338
  }
1928
2339
  const lang = langInput;
1929
2340
  config.setLanguage(lang);
1930
- console.log(chalk15.green(`\u2713 Default language set to ${lang}`));
2341
+ console.log(chalk16.green(`\u2713 Default language set to ${lang}`));
1931
2342
  }
1932
2343
  if (options.editor) {
1933
2344
  config.setEditor(options.editor);
1934
- console.log(chalk15.green(`\u2713 Editor set to ${options.editor}`));
2345
+ console.log(chalk16.green(`\u2713 Editor set to ${options.editor}`));
1935
2346
  }
1936
2347
  if (options.workdir) {
1937
2348
  config.setWorkDir(options.workdir);
1938
- console.log(chalk15.green(`\u2713 Work directory set to ${options.workdir}`));
2349
+ console.log(chalk16.green(`\u2713 Work directory set to ${options.workdir}`));
1939
2350
  }
1940
2351
  if (options.repo !== void 0) {
1941
2352
  if (options.repo.trim() === "") {
1942
2353
  config.deleteRepo();
1943
- console.log(chalk15.green("\u2713 Repository URL cleared"));
2354
+ console.log(chalk16.green("\u2713 Repository URL cleared"));
1944
2355
  } else {
1945
2356
  config.setRepo(options.repo);
1946
- console.log(chalk15.green(`\u2713 Repository URL set to ${options.repo}`));
2357
+ console.log(chalk16.green(`\u2713 Repository URL set to ${options.repo}`));
1947
2358
  }
1948
2359
  }
1949
2360
  }
1950
2361
  async function configInteractiveCommand() {
1951
2362
  const currentConfig = config.getConfig();
2363
+ const workspace = config.getActiveWorkspace();
2364
+ console.log();
2365
+ console.log(chalk16.bold.cyan(`\u{1F4C1} Configuring workspace: ${workspace}`));
2366
+ console.log(chalk16.gray("\u2500".repeat(40)));
1952
2367
  const answers = await inquirer2.prompt([
1953
2368
  {
1954
2369
  type: "list",
@@ -1985,33 +2400,34 @@ async function configInteractiveCommand() {
1985
2400
  config.deleteRepo();
1986
2401
  }
1987
2402
  console.log();
1988
- console.log(chalk15.green("\u2713 Configuration saved"));
2403
+ console.log(chalk16.green("\u2713 Configuration saved"));
1989
2404
  showCurrentConfig();
1990
2405
  }
1991
2406
  function showCurrentConfig() {
1992
2407
  const currentConfig = config.getConfig();
1993
2408
  const creds = credentials.get();
2409
+ const workspace = config.getActiveWorkspace();
1994
2410
  console.log();
1995
- console.log(chalk15.bold("LeetCode CLI Configuration"));
1996
- console.log(chalk15.gray("\u2500".repeat(40)));
2411
+ console.log(chalk16.bold.cyan(`\u{1F4C1} Workspace: ${workspace}`));
2412
+ console.log(chalk16.gray("\u2500".repeat(40)));
1997
2413
  console.log();
1998
- console.log(chalk15.gray("Config file:"), config.getPath());
2414
+ console.log(chalk16.gray("Config file:"), config.getPath());
1999
2415
  console.log();
2000
- console.log(chalk15.gray("Language: "), chalk15.white(currentConfig.language));
2001
- console.log(chalk15.gray("Editor: "), chalk15.white(currentConfig.editor ?? "(not set)"));
2002
- console.log(chalk15.gray("Work Dir: "), chalk15.white(currentConfig.workDir));
2003
- console.log(chalk15.gray("Repo URL: "), chalk15.white(currentConfig.repo ?? "(not set)"));
2004
- console.log(chalk15.gray("Logged in: "), creds ? chalk15.green("Yes") : chalk15.yellow("No"));
2416
+ console.log(chalk16.gray("Language: "), chalk16.white(currentConfig.language));
2417
+ console.log(chalk16.gray("Editor: "), chalk16.white(currentConfig.editor ?? "(not set)"));
2418
+ console.log(chalk16.gray("Work Dir: "), chalk16.white(currentConfig.workDir));
2419
+ console.log(chalk16.gray("Repo URL: "), chalk16.white(currentConfig.repo ?? "(not set)"));
2420
+ console.log(chalk16.gray("Logged in: "), creds ? chalk16.green("Yes") : chalk16.yellow("No"));
2005
2421
  }
2006
2422
 
2007
2423
  // src/commands/bookmark.ts
2008
- import chalk16 from "chalk";
2424
+ import chalk17 from "chalk";
2009
2425
  import Table2 from "cli-table3";
2010
2426
  import ora11 from "ora";
2011
2427
 
2012
2428
  // src/storage/bookmarks.ts
2013
- import Conf4 from "conf";
2014
- var bookmarksStore = new Conf4({
2429
+ import Conf2 from "conf";
2430
+ var bookmarksStore = new Conf2({
2015
2431
  projectName: "leetcode-cli-bookmarks",
2016
2432
  defaults: { bookmarks: [] }
2017
2433
  });
@@ -2050,36 +2466,36 @@ var bookmarks = {
2050
2466
  async function bookmarkCommand(action, id) {
2051
2467
  const validActions = ["add", "remove", "list", "clear"];
2052
2468
  if (!validActions.includes(action)) {
2053
- console.log(chalk16.red(`Invalid action: ${action}`));
2054
- console.log(chalk16.gray("Valid actions: add, remove, list, clear"));
2469
+ console.log(chalk17.red(`Invalid action: ${action}`));
2470
+ console.log(chalk17.gray("Valid actions: add, remove, list, clear"));
2055
2471
  return;
2056
2472
  }
2057
2473
  switch (action) {
2058
2474
  case "add":
2059
2475
  if (!id) {
2060
- console.log(chalk16.red("Please provide a problem ID to bookmark"));
2476
+ console.log(chalk17.red("Please provide a problem ID to bookmark"));
2061
2477
  return;
2062
2478
  }
2063
2479
  if (!isProblemId(id)) {
2064
- console.log(chalk16.red(`Invalid problem ID: ${id}`));
2065
- console.log(chalk16.gray("Problem ID must be a positive integer"));
2480
+ console.log(chalk17.red(`Invalid problem ID: ${id}`));
2481
+ console.log(chalk17.gray("Problem ID must be a positive integer"));
2066
2482
  return;
2067
2483
  }
2068
2484
  if (bookmarks.add(id)) {
2069
- console.log(chalk16.green(`\u2713 Bookmarked problem ${id}`));
2485
+ console.log(chalk17.green(`\u2713 Bookmarked problem ${id}`));
2070
2486
  } else {
2071
- console.log(chalk16.yellow(`Problem ${id} is already bookmarked`));
2487
+ console.log(chalk17.yellow(`Problem ${id} is already bookmarked`));
2072
2488
  }
2073
2489
  break;
2074
2490
  case "remove":
2075
2491
  if (!id) {
2076
- console.log(chalk16.red("Please provide a problem ID to remove"));
2492
+ console.log(chalk17.red("Please provide a problem ID to remove"));
2077
2493
  return;
2078
2494
  }
2079
2495
  if (bookmarks.remove(id)) {
2080
- console.log(chalk16.green(`\u2713 Removed bookmark for problem ${id}`));
2496
+ console.log(chalk17.green(`\u2713 Removed bookmark for problem ${id}`));
2081
2497
  } else {
2082
- console.log(chalk16.yellow(`Problem ${id} is not bookmarked`));
2498
+ console.log(chalk17.yellow(`Problem ${id} is not bookmarked`));
2083
2499
  }
2084
2500
  break;
2085
2501
  case "list":
@@ -2088,10 +2504,10 @@ async function bookmarkCommand(action, id) {
2088
2504
  case "clear":
2089
2505
  const count = bookmarks.count();
2090
2506
  if (count === 0) {
2091
- console.log(chalk16.yellow("No bookmarks to clear"));
2507
+ console.log(chalk17.yellow("No bookmarks to clear"));
2092
2508
  } else {
2093
2509
  bookmarks.clear();
2094
- console.log(chalk16.green(`\u2713 Cleared ${count} bookmark${count !== 1 ? "s" : ""}`));
2510
+ console.log(chalk17.green(`\u2713 Cleared ${count} bookmark${count !== 1 ? "s" : ""}`));
2095
2511
  }
2096
2512
  break;
2097
2513
  }
@@ -2099,12 +2515,12 @@ async function bookmarkCommand(action, id) {
2099
2515
  async function listBookmarks() {
2100
2516
  const bookmarkList = bookmarks.list();
2101
2517
  if (bookmarkList.length === 0) {
2102
- console.log(chalk16.yellow("\u{1F4CC} No bookmarked problems"));
2103
- console.log(chalk16.gray('Use "leetcode bookmark add <id>" to bookmark a problem'));
2518
+ console.log(chalk17.yellow("\u{1F4CC} No bookmarked problems"));
2519
+ console.log(chalk17.gray('Use "leetcode bookmark add <id>" to bookmark a problem'));
2104
2520
  return;
2105
2521
  }
2106
2522
  console.log();
2107
- console.log(chalk16.bold.cyan(`\u{1F4CC} Bookmarked Problems (${bookmarkList.length})`));
2523
+ console.log(chalk17.bold.cyan(`\u{1F4CC} Bookmarked Problems (${bookmarkList.length})`));
2108
2524
  console.log();
2109
2525
  const { authorized } = await requireAuth();
2110
2526
  if (authorized) {
@@ -2112,10 +2528,10 @@ async function listBookmarks() {
2112
2528
  try {
2113
2529
  const table = new Table2({
2114
2530
  head: [
2115
- chalk16.cyan("ID"),
2116
- chalk16.cyan("Title"),
2117
- chalk16.cyan("Difficulty"),
2118
- chalk16.cyan("Status")
2531
+ chalk17.cyan("ID"),
2532
+ chalk17.cyan("Title"),
2533
+ chalk17.cyan("Difficulty"),
2534
+ chalk17.cyan("Status")
2119
2535
  ],
2120
2536
  colWidths: [8, 45, 12, 10],
2121
2537
  style: { head: [], border: [] }
@@ -2128,35 +2544,35 @@ async function listBookmarks() {
2128
2544
  problem.questionFrontendId,
2129
2545
  problem.title.length > 42 ? problem.title.slice(0, 39) + "..." : problem.title,
2130
2546
  colorDifficulty2(problem.difficulty),
2131
- problem.status === "ac" ? chalk16.green("\u2713") : chalk16.gray("-")
2547
+ problem.status === "ac" ? chalk17.green("\u2713") : chalk17.gray("-")
2132
2548
  ]);
2133
2549
  } else {
2134
- table.push([id, chalk16.gray("(not found)"), "-", "-"]);
2550
+ table.push([id, chalk17.gray("(not found)"), "-", "-"]);
2135
2551
  }
2136
2552
  } catch {
2137
- table.push([id, chalk16.gray("(error fetching)"), "-", "-"]);
2553
+ table.push([id, chalk17.gray("(error fetching)"), "-", "-"]);
2138
2554
  }
2139
2555
  }
2140
2556
  spinner.stop();
2141
2557
  console.log(table.toString());
2142
2558
  } catch {
2143
2559
  spinner.stop();
2144
- console.log(chalk16.gray("IDs: ") + bookmarkList.join(", "));
2560
+ console.log(chalk17.gray("IDs: ") + bookmarkList.join(", "));
2145
2561
  }
2146
2562
  } else {
2147
- console.log(chalk16.gray("IDs: ") + bookmarkList.join(", "));
2563
+ console.log(chalk17.gray("IDs: ") + bookmarkList.join(", "));
2148
2564
  console.log();
2149
- console.log(chalk16.gray("Login to see problem details"));
2565
+ console.log(chalk17.gray("Login to see problem details"));
2150
2566
  }
2151
2567
  }
2152
2568
  function colorDifficulty2(difficulty) {
2153
2569
  switch (difficulty.toLowerCase()) {
2154
2570
  case "easy":
2155
- return chalk16.green(difficulty);
2571
+ return chalk17.green(difficulty);
2156
2572
  case "medium":
2157
- return chalk16.yellow(difficulty);
2573
+ return chalk17.yellow(difficulty);
2158
2574
  case "hard":
2159
- return chalk16.red(difficulty);
2575
+ return chalk17.red(difficulty);
2160
2576
  default:
2161
2577
  return difficulty;
2162
2578
  }
@@ -2165,18 +2581,18 @@ function colorDifficulty2(difficulty) {
2165
2581
  // src/commands/notes.ts
2166
2582
  import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
2167
2583
  import { join as join7 } from "path";
2168
- import { existsSync as existsSync6 } from "fs";
2169
- import chalk17 from "chalk";
2584
+ import { existsSync as existsSync8 } from "fs";
2585
+ import chalk18 from "chalk";
2170
2586
  async function notesCommand(problemId, action) {
2171
2587
  if (!isProblemId(problemId)) {
2172
- console.log(chalk17.red(`Invalid problem ID: ${problemId}`));
2173
- console.log(chalk17.gray("Problem ID must be a positive integer"));
2588
+ console.log(chalk18.red(`Invalid problem ID: ${problemId}`));
2589
+ console.log(chalk18.gray("Problem ID must be a positive integer"));
2174
2590
  return;
2175
2591
  }
2176
2592
  const noteAction = action === "view" ? "view" : "edit";
2177
2593
  const notesDir = join7(config.getWorkDir(), ".notes");
2178
2594
  const notePath = join7(notesDir, `${problemId}.md`);
2179
- if (!existsSync6(notesDir)) {
2595
+ if (!existsSync8(notesDir)) {
2180
2596
  await mkdir3(notesDir, { recursive: true });
2181
2597
  }
2182
2598
  if (noteAction === "view") {
@@ -2186,32 +2602,32 @@ async function notesCommand(problemId, action) {
2186
2602
  }
2187
2603
  }
2188
2604
  async function viewNote(notePath, problemId) {
2189
- if (!existsSync6(notePath)) {
2190
- console.log(chalk17.yellow(`No notes found for problem ${problemId}`));
2191
- console.log(chalk17.gray(`Use "leetcode note ${problemId} edit" to create notes`));
2605
+ if (!existsSync8(notePath)) {
2606
+ console.log(chalk18.yellow(`No notes found for problem ${problemId}`));
2607
+ console.log(chalk18.gray(`Use "leetcode note ${problemId} edit" to create notes`));
2192
2608
  return;
2193
2609
  }
2194
2610
  try {
2195
2611
  const content = await readFile3(notePath, "utf-8");
2196
2612
  console.log();
2197
- console.log(chalk17.bold.cyan(`\u{1F4DD} Notes for Problem ${problemId}`));
2198
- console.log(chalk17.gray("\u2500".repeat(50)));
2613
+ console.log(chalk18.bold.cyan(`\u{1F4DD} Notes for Problem ${problemId}`));
2614
+ console.log(chalk18.gray("\u2500".repeat(50)));
2199
2615
  console.log();
2200
2616
  console.log(content);
2201
2617
  } catch (error) {
2202
- console.log(chalk17.red("Failed to read notes"));
2618
+ console.log(chalk18.red("Failed to read notes"));
2203
2619
  if (error instanceof Error) {
2204
- console.log(chalk17.gray(error.message));
2620
+ console.log(chalk18.gray(error.message));
2205
2621
  }
2206
2622
  }
2207
2623
  }
2208
2624
  async function editNote(notePath, problemId) {
2209
- if (!existsSync6(notePath)) {
2625
+ if (!existsSync8(notePath)) {
2210
2626
  const template = await generateNoteTemplate(problemId);
2211
2627
  await writeFile3(notePath, template, "utf-8");
2212
- console.log(chalk17.green(`\u2713 Created notes file for problem ${problemId}`));
2628
+ console.log(chalk18.green(`\u2713 Created notes file for problem ${problemId}`));
2213
2629
  }
2214
- console.log(chalk17.gray(`Opening: ${notePath}`));
2630
+ console.log(chalk18.gray(`Opening: ${notePath}`));
2215
2631
  await openInEditor(notePath);
2216
2632
  }
2217
2633
  async function generateNoteTemplate(problemId) {
@@ -2268,7 +2684,7 @@ async function generateNoteTemplate(problemId) {
2268
2684
  }
2269
2685
 
2270
2686
  // src/commands/today.ts
2271
- import chalk18 from "chalk";
2687
+ import chalk19 from "chalk";
2272
2688
  import ora12 from "ora";
2273
2689
  async function todayCommand() {
2274
2690
  const { authorized, username } = await requireAuth();
@@ -2283,48 +2699,48 @@ async function todayCommand() {
2283
2699
  ]);
2284
2700
  spinner.stop();
2285
2701
  console.log();
2286
- console.log(chalk18.bold.cyan(`\u{1F4CA} Today's Summary`), chalk18.gray(`- ${username}`));
2287
- console.log(chalk18.gray("\u2500".repeat(50)));
2702
+ console.log(chalk19.bold.cyan(`\u{1F4CA} Today's Summary`), chalk19.gray(`- ${username}`));
2703
+ console.log(chalk19.gray("\u2500".repeat(50)));
2288
2704
  console.log();
2289
- console.log(chalk18.yellow(`\u{1F525} Current Streak: ${profile.streak} day${profile.streak !== 1 ? "s" : ""}`));
2290
- console.log(chalk18.gray(` Total Active Days: ${profile.totalActiveDays}`));
2705
+ console.log(chalk19.yellow(`\u{1F525} Current Streak: ${profile.streak} day${profile.streak !== 1 ? "s" : ""}`));
2706
+ console.log(chalk19.gray(` Total Active Days: ${profile.totalActiveDays}`));
2291
2707
  console.log();
2292
2708
  const total = profile.acSubmissionNum.find((s) => s.difficulty === "All");
2293
2709
  const easy = profile.acSubmissionNum.find((s) => s.difficulty === "Easy");
2294
2710
  const medium = profile.acSubmissionNum.find((s) => s.difficulty === "Medium");
2295
2711
  const hard = profile.acSubmissionNum.find((s) => s.difficulty === "Hard");
2296
- console.log(chalk18.white("\u{1F4C8} Problems Solved:"));
2297
- console.log(` ${chalk18.green("Easy")}: ${easy?.count ?? 0} | ${chalk18.yellow("Medium")}: ${medium?.count ?? 0} | ${chalk18.red("Hard")}: ${hard?.count ?? 0}`);
2298
- console.log(` ${chalk18.bold("Total")}: ${total?.count ?? 0}`);
2712
+ console.log(chalk19.white("\u{1F4C8} Problems Solved:"));
2713
+ console.log(` ${chalk19.green("Easy")}: ${easy?.count ?? 0} | ${chalk19.yellow("Medium")}: ${medium?.count ?? 0} | ${chalk19.red("Hard")}: ${hard?.count ?? 0}`);
2714
+ console.log(` ${chalk19.bold("Total")}: ${total?.count ?? 0}`);
2299
2715
  console.log();
2300
- console.log(chalk18.bold.yellow("\u{1F3AF} Today's Challenge:"));
2716
+ console.log(chalk19.bold.yellow("\u{1F3AF} Today's Challenge:"));
2301
2717
  console.log(` ${daily.question.questionFrontendId}. ${daily.question.title}`);
2302
2718
  console.log(` ${colorDifficulty3(daily.question.difficulty)}`);
2303
2719
  const status = daily.question.status;
2304
2720
  if (status === "ac") {
2305
- console.log(chalk18.green(" \u2713 Completed!"));
2721
+ console.log(chalk19.green(" \u2713 Completed!"));
2306
2722
  } else if (status === "notac") {
2307
- console.log(chalk18.yellow(" \u25CB Attempted"));
2723
+ console.log(chalk19.yellow(" \u25CB Attempted"));
2308
2724
  } else {
2309
- console.log(chalk18.gray(" - Not started"));
2725
+ console.log(chalk19.gray(" - Not started"));
2310
2726
  }
2311
2727
  console.log();
2312
- console.log(chalk18.gray(` leetcode pick ${daily.question.questionFrontendId} # Start working on it`));
2728
+ console.log(chalk19.gray(` leetcode pick ${daily.question.questionFrontendId} # Start working on it`));
2313
2729
  } catch (error) {
2314
2730
  spinner.fail("Failed to fetch progress");
2315
2731
  if (error instanceof Error) {
2316
- console.log(chalk18.red(error.message));
2732
+ console.log(chalk19.red(error.message));
2317
2733
  }
2318
2734
  }
2319
2735
  }
2320
2736
  function colorDifficulty3(difficulty) {
2321
2737
  switch (difficulty.toLowerCase()) {
2322
2738
  case "easy":
2323
- return chalk18.green(difficulty);
2739
+ return chalk19.green(difficulty);
2324
2740
  case "medium":
2325
- return chalk18.yellow(difficulty);
2741
+ return chalk19.yellow(difficulty);
2326
2742
  case "hard":
2327
- return chalk18.red(difficulty);
2743
+ return chalk19.red(difficulty);
2328
2744
  default:
2329
2745
  return difficulty;
2330
2746
  }
@@ -2332,8 +2748,8 @@ function colorDifficulty3(difficulty) {
2332
2748
 
2333
2749
  // src/commands/sync.ts
2334
2750
  import { execSync } from "child_process";
2335
- import { existsSync as existsSync7 } from "fs";
2336
- import chalk19 from "chalk";
2751
+ import { existsSync as existsSync9 } from "fs";
2752
+ import chalk20 from "chalk";
2337
2753
  import inquirer3 from "inquirer";
2338
2754
  import ora13 from "ora";
2339
2755
  function isGitInstalled() {
@@ -2378,7 +2794,7 @@ async function setupGitRepo(workDir) {
2378
2794
  }
2379
2795
  ]);
2380
2796
  if (!init) {
2381
- console.log(chalk19.yellow("Skipping basic git initialization."));
2797
+ console.log(chalk20.yellow("Skipping basic git initialization."));
2382
2798
  return false;
2383
2799
  }
2384
2800
  const spinner = ora13("Initializing git repository...").start();
@@ -2417,12 +2833,12 @@ async function setupRemote(workDir) {
2417
2833
  return repoUrl;
2418
2834
  } catch (error) {
2419
2835
  spinner.fail("Failed to create GitHub repository");
2420
- console.log(chalk19.red(error));
2836
+ console.log(chalk20.red(error));
2421
2837
  }
2422
2838
  }
2423
2839
  }
2424
2840
  if (!repoUrl) {
2425
- console.log(chalk19.yellow("\nPlease create a new repository on your Git provider and copy the URL."));
2841
+ console.log(chalk20.yellow("\nPlease create a new repository on your Git provider and copy the URL."));
2426
2842
  const { url } = await inquirer3.prompt([
2427
2843
  {
2428
2844
  type: "input",
@@ -2441,21 +2857,21 @@ async function setupRemote(workDir) {
2441
2857
  if (!currentRemote && repoUrl) {
2442
2858
  try {
2443
2859
  execSync(`git remote add origin ${repoUrl}`, { cwd: workDir });
2444
- console.log(chalk19.green("\u2713 Added remote origin"));
2860
+ console.log(chalk20.green("\u2713 Added remote origin"));
2445
2861
  } catch (e) {
2446
- console.log(chalk19.red("Failed to add remote origin"));
2862
+ console.log(chalk20.red("Failed to add remote origin"));
2447
2863
  }
2448
2864
  }
2449
2865
  return repoUrl || "";
2450
2866
  }
2451
2867
  async function syncCommand() {
2452
2868
  const workDir = config.getWorkDir();
2453
- if (!existsSync7(workDir)) {
2454
- console.log(chalk19.red(`Work directory does not exist: ${workDir}`));
2869
+ if (!existsSync9(workDir)) {
2870
+ console.log(chalk20.red(`Work directory does not exist: ${workDir}`));
2455
2871
  return;
2456
2872
  }
2457
2873
  if (!isGitInstalled()) {
2458
- console.log(chalk19.red("Git is not installed. Please install Git to use command."));
2874
+ console.log(chalk20.red("Git is not installed. Please install Git to use command."));
2459
2875
  return;
2460
2876
  }
2461
2877
  if (!isMapRepo(workDir)) {
@@ -2489,14 +2905,14 @@ async function syncCommand() {
2489
2905
  } catch (error) {
2490
2906
  spinner.fail("Sync failed");
2491
2907
  if (error.message) {
2492
- console.log(chalk19.red(error.message));
2908
+ console.log(chalk20.red(error.message));
2493
2909
  }
2494
2910
  }
2495
2911
  }
2496
2912
 
2497
2913
  // src/commands/timer.ts
2498
2914
  import ora14 from "ora";
2499
- import chalk20 from "chalk";
2915
+ import chalk21 from "chalk";
2500
2916
  var DEFAULT_TIMES = {
2501
2917
  Easy: 20,
2502
2918
  Medium: 40,
@@ -2525,10 +2941,10 @@ async function timerCommand(idOrSlug, options) {
2525
2941
  return;
2526
2942
  }
2527
2943
  if (!idOrSlug) {
2528
- console.log(chalk20.yellow("Please provide a problem ID to start the timer."));
2529
- console.log(chalk20.gray("Usage: leetcode timer <id>"));
2530
- console.log(chalk20.gray(" leetcode timer --stats"));
2531
- console.log(chalk20.gray(" leetcode timer --stop"));
2944
+ console.log(chalk21.yellow("Please provide a problem ID to start the timer."));
2945
+ console.log(chalk21.gray("Usage: leetcode timer <id>"));
2946
+ console.log(chalk21.gray(" leetcode timer --stats"));
2947
+ console.log(chalk21.gray(" leetcode timer --stop"));
2532
2948
  return;
2533
2949
  }
2534
2950
  const { authorized } = await requireAuth();
@@ -2537,11 +2953,11 @@ async function timerCommand(idOrSlug, options) {
2537
2953
  if (activeTimer) {
2538
2954
  const startedAt = new Date(activeTimer.startedAt);
2539
2955
  const elapsed = Math.floor((Date.now() - startedAt.getTime()) / 1e3);
2540
- console.log(chalk20.yellow("\u26A0\uFE0F You have an active timer running:"));
2541
- console.log(chalk20.white(` Problem: ${activeTimer.title}`));
2542
- console.log(chalk20.white(` Elapsed: ${formatDuration(elapsed)}`));
2956
+ console.log(chalk21.yellow("\u26A0\uFE0F You have an active timer running:"));
2957
+ console.log(chalk21.white(` Problem: ${activeTimer.title}`));
2958
+ console.log(chalk21.white(` Elapsed: ${formatDuration(elapsed)}`));
2543
2959
  console.log();
2544
- console.log(chalk20.gray("Use `leetcode timer --stop` to stop it first."));
2960
+ console.log(chalk21.gray("Use `leetcode timer --stop` to stop it first."));
2545
2961
  return;
2546
2962
  }
2547
2963
  const spinner = ora14("Fetching problem...").start();
@@ -2565,65 +2981,65 @@ async function timerCommand(idOrSlug, options) {
2565
2981
  durationMinutes
2566
2982
  );
2567
2983
  console.log();
2568
- console.log(chalk20.bold.cyan("\u23F1\uFE0F Interview Mode Started!"));
2569
- console.log(chalk20.gray("\u2500".repeat(50)));
2984
+ console.log(chalk21.bold.cyan("\u23F1\uFE0F Interview Mode Started!"));
2985
+ console.log(chalk21.gray("\u2500".repeat(50)));
2570
2986
  console.log();
2571
- console.log(chalk20.white(`Problem: ${problem.questionFrontendId}. ${problem.title}`));
2572
- console.log(chalk20.white(`Difficulty: ${chalk20.bold(problem.difficulty)}`));
2573
- console.log(chalk20.white(`Time Limit: ${chalk20.bold.yellow(durationMinutes + " minutes")}`));
2987
+ console.log(chalk21.white(`Problem: ${problem.questionFrontendId}. ${problem.title}`));
2988
+ console.log(chalk21.white(`Difficulty: ${chalk21.bold(problem.difficulty)}`));
2989
+ console.log(chalk21.white(`Time Limit: ${chalk21.bold.yellow(durationMinutes + " minutes")}`));
2574
2990
  console.log();
2575
- console.log(chalk20.gray("\u2500".repeat(50)));
2576
- console.log(chalk20.green("\u2713 Timer is running in background"));
2577
- console.log(chalk20.gray(" When you submit successfully, your time will be recorded."));
2578
- console.log(chalk20.gray(" Use `leetcode timer --stop` to cancel."));
2991
+ console.log(chalk21.gray("\u2500".repeat(50)));
2992
+ console.log(chalk21.green("\u2713 Timer is running in background"));
2993
+ console.log(chalk21.gray(" When you submit successfully, your time will be recorded."));
2994
+ console.log(chalk21.gray(" Use `leetcode timer --stop` to cancel."));
2579
2995
  console.log();
2580
2996
  await pickCommand(idOrSlug, { open: true });
2581
2997
  } catch (error) {
2582
2998
  spinner.fail("Failed to start timer");
2583
2999
  if (error instanceof Error) {
2584
- console.log(chalk20.red(error.message));
3000
+ console.log(chalk21.red(error.message));
2585
3001
  }
2586
3002
  }
2587
3003
  }
2588
3004
  async function stopActiveTimer() {
2589
3005
  const result = timerStorage.stopTimer();
2590
3006
  if (!result) {
2591
- console.log(chalk20.yellow("No active timer to stop."));
3007
+ console.log(chalk21.yellow("No active timer to stop."));
2592
3008
  return;
2593
3009
  }
2594
- console.log(chalk20.green("\u23F1\uFE0F Timer stopped."));
2595
- console.log(chalk20.gray(`Elapsed time: ${formatDuration(result.durationSeconds)}`));
2596
- console.log(chalk20.gray("(Time not recorded since problem was not submitted)"));
3010
+ console.log(chalk21.green("\u23F1\uFE0F Timer stopped."));
3011
+ console.log(chalk21.gray(`Elapsed time: ${formatDuration(result.durationSeconds)}`));
3012
+ console.log(chalk21.gray("(Time not recorded since problem was not submitted)"));
2597
3013
  }
2598
3014
  async function showTimerStats(problemId) {
2599
3015
  if (problemId && /^\d+$/.test(problemId)) {
2600
3016
  const times = timerStorage.getSolveTimes(problemId);
2601
3017
  if (times.length === 0) {
2602
- console.log(chalk20.yellow(`No solve times recorded for problem ${problemId}`));
3018
+ console.log(chalk21.yellow(`No solve times recorded for problem ${problemId}`));
2603
3019
  return;
2604
3020
  }
2605
3021
  console.log();
2606
- console.log(chalk20.bold(`\u23F1\uFE0F Solve Times for Problem ${problemId}`));
2607
- console.log(chalk20.gray("\u2500".repeat(40)));
3022
+ console.log(chalk21.bold(`\u23F1\uFE0F Solve Times for Problem ${problemId}`));
3023
+ console.log(chalk21.gray("\u2500".repeat(40)));
2608
3024
  for (const entry of times) {
2609
3025
  const date = new Date(entry.solvedAt).toLocaleDateString();
2610
3026
  const duration = formatDuration(entry.durationSeconds);
2611
3027
  const limit = entry.timerMinutes;
2612
3028
  const withinLimit = entry.durationSeconds <= limit * 60;
2613
3029
  console.log(
2614
- ` ${date} ${withinLimit ? chalk20.green(duration) : chalk20.red(duration)} (limit: ${limit}m)`
3030
+ ` ${date} ${withinLimit ? chalk21.green(duration) : chalk21.red(duration)} (limit: ${limit}m)`
2615
3031
  );
2616
3032
  }
2617
3033
  } else {
2618
3034
  const stats = timerStorage.getStats();
2619
3035
  const allTimes = timerStorage.getAllSolveTimes();
2620
3036
  console.log();
2621
- console.log(chalk20.bold("\u23F1\uFE0F Timer Statistics"));
2622
- console.log(chalk20.gray("\u2500".repeat(40)));
3037
+ console.log(chalk21.bold("\u23F1\uFE0F Timer Statistics"));
3038
+ console.log(chalk21.gray("\u2500".repeat(40)));
2623
3039
  console.log();
2624
- console.log(` Problems timed: ${chalk20.cyan(stats.totalProblems)}`);
2625
- console.log(` Total time: ${chalk20.cyan(formatDuration(stats.totalTime))}`);
2626
- console.log(` Average time: ${chalk20.cyan(formatDuration(stats.avgTime))}`);
3040
+ console.log(` Problems timed: ${chalk21.cyan(stats.totalProblems)}`);
3041
+ console.log(` Total time: ${chalk21.cyan(formatDuration(stats.totalTime))}`);
3042
+ console.log(` Average time: ${chalk21.cyan(formatDuration(stats.avgTime))}`);
2627
3043
  console.log();
2628
3044
  const recentSolves = [];
2629
3045
  for (const [id, times] of Object.entries(allTimes)) {
@@ -2638,11 +3054,11 @@ async function showTimerStats(problemId) {
2638
3054
  }
2639
3055
  if (recentSolves.length > 0) {
2640
3056
  recentSolves.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
2641
- console.log(chalk20.bold(" Recent Solves:"));
3057
+ console.log(chalk21.bold(" Recent Solves:"));
2642
3058
  for (const solve of recentSolves.slice(0, 5)) {
2643
3059
  const date = new Date(solve.date).toLocaleDateString();
2644
3060
  console.log(
2645
- chalk20.gray(` ${date} `) + chalk20.white(`${solve.problemId}. ${solve.title.substring(0, 25)}`) + chalk20.gray(" ") + chalk20.cyan(formatDuration(solve.duration))
3061
+ chalk21.gray(` ${date} `) + chalk21.white(`${solve.problemId}. ${solve.title.substring(0, 25)}`) + chalk21.gray(" ") + chalk21.cyan(formatDuration(solve.duration))
2646
3062
  );
2647
3063
  }
2648
3064
  }
@@ -2651,7 +3067,7 @@ async function showTimerStats(problemId) {
2651
3067
  }
2652
3068
 
2653
3069
  // src/commands/collab.ts
2654
- import chalk21 from "chalk";
3070
+ import chalk22 from "chalk";
2655
3071
  import ora15 from "ora";
2656
3072
  import { readFile as readFile4 } from "fs/promises";
2657
3073
 
@@ -2662,29 +3078,35 @@ var SUPABASE_ANON_KEY = "sb_publishable_indrKu8VJmASdyLp7w8Hog_OyqT17cV";
2662
3078
  var supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
2663
3079
 
2664
3080
  // src/storage/collab.ts
2665
- import Conf5 from "conf";
2666
- import { homedir as homedir4 } from "os";
2667
- import { join as join8 } from "path";
2668
- var collabStore = new Conf5({
2669
- configName: "collab",
2670
- cwd: join8(homedir4(), ".leetcode"),
2671
- defaults: {
2672
- session: null
3081
+ import { existsSync as existsSync10, readFileSync as readFileSync3, writeFileSync as writeFileSync4, mkdirSync as mkdirSync3 } from "fs";
3082
+ import { dirname as dirname2 } from "path";
3083
+ function getCollabPath() {
3084
+ return workspaceStorage.getCollabPath();
3085
+ }
3086
+ function loadCollab() {
3087
+ const path = getCollabPath();
3088
+ if (existsSync10(path)) {
3089
+ return JSON.parse(readFileSync3(path, "utf-8"));
2673
3090
  }
2674
- });
3091
+ return { session: null };
3092
+ }
3093
+ function saveCollab(data) {
3094
+ const collabPath = getCollabPath();
3095
+ const dir = dirname2(collabPath);
3096
+ if (!existsSync10(dir)) {
3097
+ mkdirSync3(dir, { recursive: true });
3098
+ }
3099
+ writeFileSync4(collabPath, JSON.stringify(data, null, 2));
3100
+ }
2675
3101
  var collabStorage = {
2676
3102
  getSession() {
2677
- return collabStore.get("session");
3103
+ return loadCollab().session;
2678
3104
  },
2679
3105
  setSession(session) {
2680
- if (session) {
2681
- collabStore.set("session", session);
2682
- } else {
2683
- collabStore.delete("session");
2684
- }
3106
+ saveCollab({ session });
2685
3107
  },
2686
3108
  getPath() {
2687
- return collabStore.path;
3109
+ return getCollabPath();
2688
3110
  }
2689
3111
  };
2690
3112
 
@@ -2812,27 +3234,27 @@ async function collabHostCommand(problemId) {
2812
3234
  }
2813
3235
  spinner.succeed("Room created!");
2814
3236
  console.log();
2815
- console.log(chalk21.bold.cyan("\u{1F465} Collaborative Coding Session"));
2816
- console.log(chalk21.gray("\u2500".repeat(50)));
3237
+ console.log(chalk22.bold.cyan("\u{1F465} Collaborative Coding Session"));
3238
+ console.log(chalk22.gray("\u2500".repeat(50)));
2817
3239
  console.log();
2818
- console.log(chalk21.white(`Room Code: ${chalk21.bold.green(result.roomCode)}`));
2819
- console.log(chalk21.white(`Problem: ${problemId}`));
3240
+ console.log(chalk22.white(`Room Code: ${chalk22.bold.green(result.roomCode)}`));
3241
+ console.log(chalk22.white(`Problem: ${problemId}`));
2820
3242
  console.log();
2821
- console.log(chalk21.gray("Share this code with your partner:"));
2822
- console.log(chalk21.yellow(` leetcode collab join ${result.roomCode}`));
3243
+ console.log(chalk22.gray("Share this code with your partner:"));
3244
+ console.log(chalk22.yellow(` leetcode collab join ${result.roomCode}`));
2823
3245
  console.log();
2824
- console.log(chalk21.gray("\u2500".repeat(50)));
2825
- console.log(chalk21.gray("After solving, sync and compare:"));
2826
- console.log(chalk21.gray(" leetcode collab sync - Upload your solution"));
2827
- console.log(chalk21.gray(" leetcode collab compare - See both solutions"));
2828
- console.log(chalk21.gray(" leetcode collab status - Check room status"));
2829
- console.log(chalk21.gray(" leetcode collab leave - End session"));
3246
+ console.log(chalk22.gray("\u2500".repeat(50)));
3247
+ console.log(chalk22.gray("After solving, sync and compare:"));
3248
+ console.log(chalk22.gray(" leetcode collab sync - Upload your solution"));
3249
+ console.log(chalk22.gray(" leetcode collab compare - See both solutions"));
3250
+ console.log(chalk22.gray(" leetcode collab status - Check room status"));
3251
+ console.log(chalk22.gray(" leetcode collab leave - End session"));
2830
3252
  console.log();
2831
3253
  await pickCommand(problemId, { open: true });
2832
3254
  } catch (error) {
2833
3255
  spinner.fail("Failed to create room");
2834
3256
  if (error instanceof Error) {
2835
- console.log(chalk21.red(error.message));
3257
+ console.log(chalk22.red(error.message));
2836
3258
  }
2837
3259
  }
2838
3260
  }
@@ -2848,32 +3270,32 @@ async function collabJoinCommand(roomCode) {
2848
3270
  }
2849
3271
  spinner.succeed("Joined room!");
2850
3272
  console.log();
2851
- console.log(chalk21.bold.cyan("\u{1F465} Collaborative Coding Session"));
2852
- console.log(chalk21.gray("\u2500".repeat(50)));
3273
+ console.log(chalk22.bold.cyan("\u{1F465} Collaborative Coding Session"));
3274
+ console.log(chalk22.gray("\u2500".repeat(50)));
2853
3275
  console.log();
2854
- console.log(chalk21.white(`Room Code: ${chalk21.bold.green(roomCode.toUpperCase())}`));
2855
- console.log(chalk21.white(`Problem: ${result.problemId}`));
3276
+ console.log(chalk22.white(`Room Code: ${chalk22.bold.green(roomCode.toUpperCase())}`));
3277
+ console.log(chalk22.white(`Problem: ${result.problemId}`));
2856
3278
  console.log();
2857
- console.log(chalk21.gray("\u2500".repeat(50)));
2858
- console.log(chalk21.gray("After solving, sync and compare:"));
2859
- console.log(chalk21.gray(" leetcode collab sync - Upload your solution"));
2860
- console.log(chalk21.gray(" leetcode collab compare - See both solutions"));
2861
- console.log(chalk21.gray(" leetcode collab status - Check room status"));
2862
- console.log(chalk21.gray(" leetcode collab leave - End session"));
3279
+ console.log(chalk22.gray("\u2500".repeat(50)));
3280
+ console.log(chalk22.gray("After solving, sync and compare:"));
3281
+ console.log(chalk22.gray(" leetcode collab sync - Upload your solution"));
3282
+ console.log(chalk22.gray(" leetcode collab compare - See both solutions"));
3283
+ console.log(chalk22.gray(" leetcode collab status - Check room status"));
3284
+ console.log(chalk22.gray(" leetcode collab leave - End session"));
2863
3285
  console.log();
2864
3286
  await pickCommand(result.problemId, { open: true });
2865
3287
  } catch (error) {
2866
3288
  spinner.fail("Failed to join room");
2867
3289
  if (error instanceof Error) {
2868
- console.log(chalk21.red(error.message));
3290
+ console.log(chalk22.red(error.message));
2869
3291
  }
2870
3292
  }
2871
3293
  }
2872
3294
  async function collabSyncCommand() {
2873
3295
  const session = collabService.getSession();
2874
3296
  if (!session) {
2875
- console.log(chalk21.yellow("No active collaboration session."));
2876
- console.log(chalk21.gray("Use `leetcode collab host <id>` or `leetcode collab join <code>` first."));
3297
+ console.log(chalk22.yellow("No active collaboration session."));
3298
+ console.log(chalk22.gray("Use `leetcode collab host <id>` or `leetcode collab join <code>` first."));
2877
3299
  return;
2878
3300
  }
2879
3301
  const spinner = ora15("Syncing your code...").start();
@@ -2887,7 +3309,7 @@ async function collabSyncCommand() {
2887
3309
  const result = await collabService.syncCode(code);
2888
3310
  if (result.success) {
2889
3311
  spinner.succeed("Code synced successfully!");
2890
- console.log(chalk21.gray(`Uploaded ${code.split("\n").length} lines from ${filePath}`));
3312
+ console.log(chalk22.gray(`Uploaded ${code.split("\n").length} lines from ${filePath}`));
2891
3313
  } else {
2892
3314
  spinner.fail(result.error || "Sync failed");
2893
3315
  }
@@ -2895,8 +3317,8 @@ async function collabSyncCommand() {
2895
3317
  async function collabCompareCommand() {
2896
3318
  const session = collabService.getSession();
2897
3319
  if (!session) {
2898
- console.log(chalk21.yellow("No active collaboration session."));
2899
- console.log(chalk21.gray("Use `leetcode collab host <id>` or `leetcode collab join <code>` first."));
3320
+ console.log(chalk22.yellow("No active collaboration session."));
3321
+ console.log(chalk22.gray("Use `leetcode collab host <id>` or `leetcode collab join <code>` first."));
2900
3322
  return;
2901
3323
  }
2902
3324
  const spinner = ora15("Fetching solutions...").start();
@@ -2914,224 +3336,778 @@ async function collabCompareCommand() {
2914
3336
  }
2915
3337
  spinner.stop();
2916
3338
  if (!partnerResult.code) {
2917
- console.log(chalk21.yellow("Partner has not synced their code yet."));
2918
- console.log(chalk21.gray("Ask them to run `leetcode collab sync`."));
3339
+ console.log(chalk22.yellow("Partner has not synced their code yet."));
3340
+ console.log(chalk22.gray("Ask them to run `leetcode collab sync`."));
2919
3341
  return;
2920
3342
  }
2921
3343
  console.log();
2922
- console.log(chalk21.bold.cyan("\u{1F4CA} Solution Comparison"));
2923
- console.log(chalk21.gray("\u2500".repeat(60)));
3344
+ console.log(chalk22.bold.cyan("\u{1F4CA} Solution Comparison"));
3345
+ console.log(chalk22.gray("\u2500".repeat(60)));
2924
3346
  console.log();
2925
- console.log(chalk21.bold.green(`\u25B8 Your Solution (${session.username})`));
2926
- console.log(chalk21.gray("\u2500".repeat(60)));
3347
+ console.log(chalk22.bold.green(`\u25B8 Your Solution (${session.username})`));
3348
+ console.log(chalk22.gray("\u2500".repeat(60)));
2927
3349
  const myLines = myCode.split("\n");
2928
3350
  for (let i = 0; i < myLines.length; i++) {
2929
3351
  const lineNum = String(i + 1).padStart(3, " ");
2930
- console.log(`${chalk21.gray(lineNum)} ${myLines[i]}`);
3352
+ console.log(`${chalk22.gray(lineNum)} ${myLines[i]}`);
2931
3353
  }
2932
3354
  console.log();
2933
- console.log(chalk21.bold.blue(`\u25B8 ${partnerResult.username}'s Solution`));
2934
- console.log(chalk21.gray("\u2500".repeat(60)));
3355
+ console.log(chalk22.bold.blue(`\u25B8 ${partnerResult.username}'s Solution`));
3356
+ console.log(chalk22.gray("\u2500".repeat(60)));
2935
3357
  const partnerLines = partnerResult.code.split("\n");
2936
3358
  for (let i = 0; i < partnerLines.length; i++) {
2937
3359
  const lineNum = String(i + 1).padStart(3, " ");
2938
- console.log(`${chalk21.gray(lineNum)} ${partnerLines[i]}`);
3360
+ console.log(`${chalk22.gray(lineNum)} ${partnerLines[i]}`);
2939
3361
  }
2940
3362
  console.log();
2941
- console.log(chalk21.gray("\u2500".repeat(60)));
2942
- console.log(chalk21.gray(`Your code: ${myLines.length} lines | Partner: ${partnerLines.length} lines`));
3363
+ console.log(chalk22.gray("\u2500".repeat(60)));
3364
+ console.log(chalk22.gray(`Your code: ${myLines.length} lines | Partner: ${partnerLines.length} lines`));
2943
3365
  console.log();
2944
3366
  }
2945
3367
  async function collabLeaveCommand() {
2946
3368
  const session = collabService.getSession();
2947
3369
  if (!session) {
2948
- console.log(chalk21.yellow("No active collaboration session."));
3370
+ console.log(chalk22.yellow("No active collaboration session."));
2949
3371
  return;
2950
3372
  }
2951
3373
  await collabService.leaveRoom();
2952
- console.log(chalk21.green("\u2713 Left the collaboration session."));
3374
+ console.log(chalk22.green("\u2713 Left the collaboration session."));
2953
3375
  }
2954
3376
  async function collabStatusCommand() {
2955
3377
  const session = collabService.getSession();
2956
3378
  if (!session) {
2957
- console.log(chalk21.yellow("No active collaboration session."));
2958
- console.log(chalk21.gray("Use `leetcode collab host <id>` or `leetcode collab join <code>` to start."));
3379
+ console.log(chalk22.yellow("No active collaboration session."));
3380
+ console.log(chalk22.gray("Use `leetcode collab host <id>` or `leetcode collab join <code>` to start."));
2959
3381
  return;
2960
3382
  }
2961
3383
  const status = await collabService.getRoomStatus();
2962
3384
  if ("error" in status) {
2963
- console.log(chalk21.red(status.error));
3385
+ console.log(chalk22.red(status.error));
2964
3386
  return;
2965
3387
  }
2966
3388
  console.log();
2967
- console.log(chalk21.bold.cyan("\u{1F465} Collaboration Status"));
2968
- console.log(chalk21.gray("\u2500".repeat(40)));
2969
- console.log(` Room: ${chalk21.green(session.roomCode)}`);
3389
+ console.log(chalk22.bold.cyan("\u{1F465} Collaboration Status"));
3390
+ console.log(chalk22.gray("\u2500".repeat(40)));
3391
+ console.log(` Room: ${chalk22.green(session.roomCode)}`);
2970
3392
  console.log(` Problem: ${session.problemId}`);
2971
3393
  console.log(` Role: ${session.isHost ? "Host" : "Guest"}`);
2972
3394
  console.log();
2973
- console.log(chalk21.bold(" Participants:"));
2974
- console.log(` Host: ${status.host} ${status.hasHostCode ? chalk21.green("\u2713 synced") : chalk21.gray("pending")}`);
2975
- console.log(` Guest: ${status.guest || chalk21.gray("(waiting...)")} ${status.hasGuestCode ? chalk21.green("\u2713 synced") : chalk21.gray("pending")}`);
3395
+ console.log(chalk22.bold(" Participants:"));
3396
+ console.log(` Host: ${status.host} ${status.hasHostCode ? chalk22.green("\u2713 synced") : chalk22.gray("pending")}`);
3397
+ console.log(` Guest: ${status.guest || chalk22.gray("(waiting...)")} ${status.hasGuestCode ? chalk22.green("\u2713 synced") : chalk22.gray("pending")}`);
3398
+ console.log();
3399
+ }
3400
+
3401
+ // src/commands/snapshot.ts
3402
+ import chalk23 from "chalk";
3403
+
3404
+ // src/storage/snapshots.ts
3405
+ import { existsSync as existsSync11, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync5, unlinkSync } from "fs";
3406
+ import { join as join8 } from "path";
3407
+ function getSnapshotsDir() {
3408
+ return workspaceStorage.getSnapshotsDir();
3409
+ }
3410
+ function getSnapshotDir(problemId) {
3411
+ return join8(getSnapshotsDir(), problemId);
3412
+ }
3413
+ function getMetaPath(problemId) {
3414
+ return join8(getSnapshotDir(problemId), "meta.json");
3415
+ }
3416
+ function getFilesDir(problemId) {
3417
+ return join8(getSnapshotDir(problemId), "files");
3418
+ }
3419
+ function ensureSnapshotDir(problemId) {
3420
+ const dir = getFilesDir(problemId);
3421
+ if (!existsSync11(dir)) {
3422
+ mkdirSync4(dir, { recursive: true });
3423
+ }
3424
+ }
3425
+ function loadMeta(problemId) {
3426
+ const metaPath = getMetaPath(problemId);
3427
+ if (existsSync11(metaPath)) {
3428
+ return JSON.parse(readFileSync4(metaPath, "utf-8"));
3429
+ }
3430
+ return {
3431
+ problemId,
3432
+ problemTitle: "",
3433
+ snapshots: []
3434
+ };
3435
+ }
3436
+ function saveMeta(problemId, meta) {
3437
+ ensureSnapshotDir(problemId);
3438
+ writeFileSync5(getMetaPath(problemId), JSON.stringify(meta, null, 2));
3439
+ }
3440
+ var snapshotStorage = {
3441
+ /**
3442
+ * Save a snapshot of the solution
3443
+ */
3444
+ save(problemId, problemTitle, code, language, name) {
3445
+ ensureSnapshotDir(problemId);
3446
+ const meta = loadMeta(problemId);
3447
+ if (problemTitle) {
3448
+ meta.problemTitle = problemTitle;
3449
+ }
3450
+ const nextId = meta.snapshots.length > 0 ? Math.max(...meta.snapshots.map((s) => s.id)) + 1 : 1;
3451
+ const snapshotName = name || `snapshot-${nextId}`;
3452
+ const existing = meta.snapshots.find((s) => s.name === snapshotName);
3453
+ if (existing) {
3454
+ return { error: `Snapshot with name "${snapshotName}" already exists (ID: ${existing.id})` };
3455
+ }
3456
+ const ext = LANGUAGE_EXTENSIONS[language] || language;
3457
+ const fileName = `${nextId}_${snapshotName}.${ext}`;
3458
+ const filePath = join8(getFilesDir(problemId), fileName);
3459
+ writeFileSync5(filePath, code, "utf-8");
3460
+ const snapshot = {
3461
+ id: nextId,
3462
+ name: snapshotName,
3463
+ fileName,
3464
+ language,
3465
+ lines: code.split("\n").length,
3466
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
3467
+ };
3468
+ meta.snapshots.push(snapshot);
3469
+ saveMeta(problemId, meta);
3470
+ return snapshot;
3471
+ },
3472
+ /**
3473
+ * Get all snapshots for a problem
3474
+ */
3475
+ list(problemId) {
3476
+ const meta = loadMeta(problemId);
3477
+ return meta.snapshots;
3478
+ },
3479
+ /**
3480
+ * Get snapshot metadata
3481
+ */
3482
+ getMeta(problemId) {
3483
+ return loadMeta(problemId);
3484
+ },
3485
+ /**
3486
+ * Get a specific snapshot by ID or name
3487
+ */
3488
+ get(problemId, idOrName) {
3489
+ const meta = loadMeta(problemId);
3490
+ const byId = meta.snapshots.find((s) => s.id === parseInt(idOrName, 10));
3491
+ if (byId) return byId;
3492
+ const byName = meta.snapshots.find((s) => s.name === idOrName);
3493
+ return byName || null;
3494
+ },
3495
+ /**
3496
+ * Get snapshot code content
3497
+ */
3498
+ getCode(problemId, snapshot) {
3499
+ const filePath = join8(getFilesDir(problemId), snapshot.fileName);
3500
+ if (!existsSync11(filePath)) {
3501
+ throw new Error(`Snapshot file not found: ${snapshot.fileName}`);
3502
+ }
3503
+ return readFileSync4(filePath, "utf-8");
3504
+ },
3505
+ /**
3506
+ * Delete a snapshot
3507
+ */
3508
+ delete(problemId, idOrName) {
3509
+ const meta = loadMeta(problemId);
3510
+ const snapshot = this.get(problemId, idOrName);
3511
+ if (!snapshot) {
3512
+ return false;
3513
+ }
3514
+ const filePath = join8(getFilesDir(problemId), snapshot.fileName);
3515
+ if (existsSync11(filePath)) {
3516
+ unlinkSync(filePath);
3517
+ }
3518
+ meta.snapshots = meta.snapshots.filter((s) => s.id !== snapshot.id);
3519
+ saveMeta(problemId, meta);
3520
+ return true;
3521
+ },
3522
+ /**
3523
+ * Check if snapshots exist for a problem
3524
+ */
3525
+ hasSnapshots(problemId) {
3526
+ return this.list(problemId).length > 0;
3527
+ }
3528
+ };
3529
+
3530
+ // src/commands/snapshot.ts
3531
+ import { readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
3532
+ import { extname, basename as basename3 } from "path";
3533
+ import { diffLines } from "diff";
3534
+ function formatTimeAgo(dateStr) {
3535
+ const date = new Date(dateStr);
3536
+ const now = /* @__PURE__ */ new Date();
3537
+ const diffMs = now.getTime() - date.getTime();
3538
+ const diffMins = Math.floor(diffMs / 6e4);
3539
+ const diffHours = Math.floor(diffMins / 60);
3540
+ const diffDays = Math.floor(diffHours / 24);
3541
+ if (diffMins < 1) return "just now";
3542
+ if (diffMins < 60) return `${diffMins}m ago`;
3543
+ if (diffHours < 24) return `${diffHours}h ago`;
3544
+ return `${diffDays}d ago`;
3545
+ }
3546
+ async function snapshotSaveCommand(problemId, name) {
3547
+ const workDir = config.getWorkDir();
3548
+ try {
3549
+ const filePath = await findSolutionFile(workDir, problemId);
3550
+ if (!filePath) {
3551
+ console.log(chalk23.red(`No solution file found for problem ${problemId}`));
3552
+ console.log(chalk23.gray("Run `leetcode pick " + problemId + "` first to create a solution file."));
3553
+ return;
3554
+ }
3555
+ const code = await readFile5(filePath, "utf-8");
3556
+ const ext = extname(filePath).slice(1);
3557
+ const lang = getLangSlugFromExtension(ext) || ext;
3558
+ const fileName = basename3(filePath);
3559
+ const titleMatch = fileName.match(/^\d+\.(.+)\.\w+$/);
3560
+ const title = titleMatch ? titleMatch[1] : "";
3561
+ const result = snapshotStorage.save(problemId, title, code, lang, name);
3562
+ if ("error" in result) {
3563
+ console.log(chalk23.red("\u2717 " + result.error));
3564
+ return;
3565
+ }
3566
+ const snapshot = result;
3567
+ console.log(chalk23.green("\u2713 Snapshot saved!"));
3568
+ console.log();
3569
+ console.log(` ID: ${chalk23.cyan(snapshot.id)}`);
3570
+ console.log(` Name: ${chalk23.white(snapshot.name)}`);
3571
+ console.log(` Lines: ${chalk23.gray(snapshot.lines)}`);
3572
+ console.log(` File: ${chalk23.gray(filePath)}`);
3573
+ } catch (error) {
3574
+ console.log(chalk23.red("Failed to save snapshot"));
3575
+ if (error instanceof Error) {
3576
+ console.log(chalk23.gray(error.message));
3577
+ }
3578
+ }
3579
+ }
3580
+ async function snapshotListCommand(problemId) {
3581
+ const snapshots = snapshotStorage.list(problemId);
3582
+ if (snapshots.length === 0) {
3583
+ console.log(chalk23.yellow(`No snapshots found for problem ${problemId}`));
3584
+ console.log(chalk23.gray("Use `leetcode snapshot save " + problemId + "` to create one."));
3585
+ return;
3586
+ }
3587
+ const meta = snapshotStorage.getMeta(problemId);
3588
+ console.log();
3589
+ console.log(chalk23.bold(`\u{1F4F8} Snapshots for Problem ${problemId}`));
3590
+ if (meta.problemTitle) {
3591
+ console.log(chalk23.gray(` ${meta.problemTitle}`));
3592
+ }
3593
+ console.log(chalk23.gray("\u2500".repeat(50)));
3594
+ console.log();
3595
+ for (const snap of snapshots) {
3596
+ const timeAgo = formatTimeAgo(snap.createdAt);
3597
+ console.log(
3598
+ ` ${chalk23.cyan(snap.id.toString().padStart(2))}. ${chalk23.white(snap.name.padEnd(25))} ${chalk23.gray(snap.lines + " lines")} ${chalk23.gray("\xB7")} ${chalk23.gray(timeAgo)}`
3599
+ );
3600
+ }
3601
+ console.log();
3602
+ console.log(chalk23.gray("Commands:"));
3603
+ console.log(chalk23.gray(` restore: leetcode snapshot restore ${problemId} <id|name>`));
3604
+ console.log(chalk23.gray(` diff: leetcode snapshot diff ${problemId} <id1> <id2>`));
3605
+ console.log(chalk23.gray(` delete: leetcode snapshot delete ${problemId} <id|name>`));
3606
+ }
3607
+ async function snapshotRestoreCommand(problemId, idOrName) {
3608
+ const workDir = config.getWorkDir();
3609
+ try {
3610
+ const snapshot = snapshotStorage.get(problemId, idOrName);
3611
+ if (!snapshot) {
3612
+ console.log(chalk23.red(`Snapshot "${idOrName}" not found for problem ${problemId}`));
3613
+ console.log(chalk23.gray("Run `leetcode snapshot list " + problemId + "` to see available snapshots."));
3614
+ return;
3615
+ }
3616
+ const filePath = await findSolutionFile(workDir, problemId);
3617
+ if (!filePath) {
3618
+ console.log(chalk23.red(`No solution file found for problem ${problemId}`));
3619
+ return;
3620
+ }
3621
+ const currentCode = await readFile5(filePath, "utf-8");
3622
+ const backupName = `backup-before-restore-${Date.now()}`;
3623
+ const ext = extname(filePath).slice(1);
3624
+ const lang = getLangSlugFromExtension(ext) || ext;
3625
+ snapshotStorage.save(problemId, "", currentCode, lang, backupName);
3626
+ const snapshotCode = snapshotStorage.getCode(problemId, snapshot);
3627
+ await writeFile4(filePath, snapshotCode, "utf-8");
3628
+ console.log(chalk23.green("\u2713 Snapshot restored!"));
3629
+ console.log();
3630
+ console.log(` Restored: ${chalk23.cyan(snapshot.name)} (${snapshot.lines} lines)`);
3631
+ console.log(` File: ${chalk23.gray(filePath)}`);
3632
+ console.log(` Backup: ${chalk23.gray(backupName)}`);
3633
+ } catch (error) {
3634
+ console.log(chalk23.red("Failed to restore snapshot"));
3635
+ if (error instanceof Error) {
3636
+ console.log(chalk23.gray(error.message));
3637
+ }
3638
+ }
3639
+ }
3640
+ async function snapshotDiffCommand(problemId, idOrName1, idOrName2) {
3641
+ try {
3642
+ const snap1 = snapshotStorage.get(problemId, idOrName1);
3643
+ const snap2 = snapshotStorage.get(problemId, idOrName2);
3644
+ if (!snap1) {
3645
+ console.log(chalk23.red(`Snapshot "${idOrName1}" not found`));
3646
+ return;
3647
+ }
3648
+ if (!snap2) {
3649
+ console.log(chalk23.red(`Snapshot "${idOrName2}" not found`));
3650
+ return;
3651
+ }
3652
+ const code1 = snapshotStorage.getCode(problemId, snap1);
3653
+ const code2 = snapshotStorage.getCode(problemId, snap2);
3654
+ console.log();
3655
+ console.log(chalk23.bold(`\u{1F4CA} Diff: ${snap1.name} \u2192 ${snap2.name}`));
3656
+ console.log(chalk23.gray("\u2500".repeat(50)));
3657
+ console.log();
3658
+ const diff = diffLines(code1, code2);
3659
+ let added = 0;
3660
+ let removed = 0;
3661
+ for (const part of diff) {
3662
+ const lines = part.value.split("\n").filter((l) => l !== "");
3663
+ if (part.added) {
3664
+ added += lines.length;
3665
+ for (const line of lines) {
3666
+ console.log(chalk23.green("+ " + line));
3667
+ }
3668
+ } else if (part.removed) {
3669
+ removed += lines.length;
3670
+ for (const line of lines) {
3671
+ console.log(chalk23.red("- " + line));
3672
+ }
3673
+ } else {
3674
+ if (lines.length <= 4) {
3675
+ for (const line of lines) {
3676
+ console.log(chalk23.gray(" " + line));
3677
+ }
3678
+ } else {
3679
+ console.log(chalk23.gray(" " + lines[0]));
3680
+ console.log(chalk23.gray(" " + lines[1]));
3681
+ console.log(chalk23.gray(` ... (${lines.length - 4} more lines)`));
3682
+ console.log(chalk23.gray(" " + lines[lines.length - 2]));
3683
+ console.log(chalk23.gray(" " + lines[lines.length - 1]));
3684
+ }
3685
+ }
3686
+ }
3687
+ console.log();
3688
+ console.log(chalk23.gray("\u2500".repeat(50)));
3689
+ console.log(
3690
+ `${chalk23.green("+" + added + " added")} ${chalk23.gray("\xB7")} ${chalk23.red("-" + removed + " removed")} ${chalk23.gray("\xB7")} ${chalk23.gray(snap1.lines + " \u2192 " + snap2.lines + " lines")}`
3691
+ );
3692
+ } catch (error) {
3693
+ console.log(chalk23.red("Failed to diff snapshots"));
3694
+ if (error instanceof Error) {
3695
+ console.log(chalk23.gray(error.message));
3696
+ }
3697
+ }
3698
+ }
3699
+ async function snapshotDeleteCommand(problemId, idOrName) {
3700
+ const snapshot = snapshotStorage.get(problemId, idOrName);
3701
+ if (!snapshot) {
3702
+ console.log(chalk23.red(`Snapshot "${idOrName}" not found for problem ${problemId}`));
3703
+ return;
3704
+ }
3705
+ const deleted = snapshotStorage.delete(problemId, idOrName);
3706
+ if (deleted) {
3707
+ console.log(chalk23.green(`\u2713 Deleted snapshot: ${snapshot.name}`));
3708
+ } else {
3709
+ console.log(chalk23.red("Failed to delete snapshot"));
3710
+ }
3711
+ }
3712
+
3713
+ // src/commands/diff.ts
3714
+ import ora16 from "ora";
3715
+ import chalk24 from "chalk";
3716
+ import { readFile as readFile6 } from "fs/promises";
3717
+ import { existsSync as existsSync12 } from "fs";
3718
+ import { diffLines as diffLines2 } from "diff";
3719
+ function showCodeBlock(code, label) {
3720
+ const lines = code.split("\n");
3721
+ const lineCount = lines.length;
3722
+ console.log();
3723
+ console.log(chalk24.bold.cyan(`=== ${label} (${lineCount} lines) ===`));
3724
+ console.log(chalk24.gray("\u2500".repeat(60)));
3725
+ lines.forEach((line, i) => {
3726
+ const lineNum = (i + 1).toString().padStart(3);
3727
+ console.log(chalk24.gray(lineNum + " \u2502 ") + line);
3728
+ });
3729
+ }
3730
+ function showUnifiedDiff(sourceCode, targetCode, sourceLabel, targetLabel) {
3731
+ const sourceLines = sourceCode.split("\n").length;
3732
+ const targetLines = targetCode.split("\n").length;
3733
+ console.log();
3734
+ console.log(chalk24.bold(`\u{1F4CA} Unified Diff: ${sourceLabel} \u2192 ${targetLabel}`));
3735
+ console.log(chalk24.gray("\u2500".repeat(60)));
3736
+ console.log();
3737
+ const diff = diffLines2(sourceCode, targetCode);
3738
+ let added = 0;
3739
+ let removed = 0;
3740
+ for (const part of diff) {
3741
+ const lines = part.value.split("\n").filter((l) => l !== "");
3742
+ if (part.added) {
3743
+ added += lines.length;
3744
+ for (const line of lines) {
3745
+ console.log(chalk24.green("+ " + line));
3746
+ }
3747
+ } else if (part.removed) {
3748
+ removed += lines.length;
3749
+ for (const line of lines) {
3750
+ console.log(chalk24.red("- " + line));
3751
+ }
3752
+ } else {
3753
+ if (lines.length <= 6) {
3754
+ for (const line of lines) {
3755
+ console.log(chalk24.gray(" " + line));
3756
+ }
3757
+ } else {
3758
+ console.log(chalk24.gray(" " + lines[0]));
3759
+ console.log(chalk24.gray(" " + lines[1]));
3760
+ console.log(chalk24.dim(` ... (${lines.length - 4} unchanged lines)`));
3761
+ console.log(chalk24.gray(" " + lines[lines.length - 2]));
3762
+ console.log(chalk24.gray(" " + lines[lines.length - 1]));
3763
+ }
3764
+ }
3765
+ }
3766
+ console.log();
3767
+ console.log(chalk24.gray("\u2500".repeat(60)));
3768
+ console.log(
3769
+ `${chalk24.green("+" + added + " added")} ${chalk24.gray("\xB7")} ${chalk24.red("-" + removed + " removed")} ${chalk24.gray("\xB7")} ${chalk24.gray(sourceLines + " \u2192 " + targetLines + " lines")}`
3770
+ );
3771
+ }
3772
+ function showComparison(sourceCode, targetCode, sourceLabel, targetLabel, unified) {
3773
+ if (unified) {
3774
+ showUnifiedDiff(sourceCode, targetCode, sourceLabel, targetLabel);
3775
+ } else {
3776
+ showCodeBlock(sourceCode, sourceLabel);
3777
+ showCodeBlock(targetCode, targetLabel);
3778
+ const diff = diffLines2(sourceCode, targetCode);
3779
+ let added = 0;
3780
+ let removed = 0;
3781
+ for (const part of diff) {
3782
+ const lines = part.value.split("\n").filter((l) => l !== "");
3783
+ if (part.added) added += lines.length;
3784
+ else if (part.removed) removed += lines.length;
3785
+ }
3786
+ console.log();
3787
+ console.log(chalk24.gray("\u2500".repeat(60)));
3788
+ console.log(
3789
+ `${chalk24.bold("Summary:")} ${chalk24.green("+" + added + " added")} ${chalk24.gray("\xB7")} ${chalk24.red("-" + removed + " removed")}`
3790
+ );
3791
+ console.log(chalk24.gray("Tip: Use --unified for line-by-line diff"));
3792
+ }
3793
+ }
3794
+ async function diffCommand(problemId, options) {
3795
+ const { authorized } = await requireAuth();
3796
+ if (!authorized) return;
3797
+ const workDir = config.getWorkDir();
3798
+ const spinner = ora16("Finding solution file...").start();
3799
+ try {
3800
+ const filePath = await findSolutionFile(workDir, problemId);
3801
+ if (!filePath) {
3802
+ spinner.fail(`No solution file found for problem ${problemId}`);
3803
+ console.log(chalk24.gray("Run `leetcode pick " + problemId + "` first to create a solution file."));
3804
+ return;
3805
+ }
3806
+ const currentCode = await readFile6(filePath, "utf-8");
3807
+ spinner.text = "Fetching comparison target...";
3808
+ if (options.file) {
3809
+ spinner.stop();
3810
+ if (!existsSync12(options.file)) {
3811
+ console.log(chalk24.red(`File not found: ${options.file}`));
3812
+ return;
3813
+ }
3814
+ const otherCode = await readFile6(options.file, "utf-8");
3815
+ showComparison(currentCode, otherCode, "Your Solution", options.file, options.unified ?? false);
3816
+ return;
3817
+ }
3818
+ const problem = await leetcodeClient.getProblemById(problemId);
3819
+ if (!problem) {
3820
+ spinner.fail(`Problem ${problemId} not found`);
3821
+ return;
3822
+ }
3823
+ if (options.submission) {
3824
+ const submissionId = parseInt(options.submission, 10);
3825
+ const submission = await leetcodeClient.getSubmissionDetails(submissionId);
3826
+ spinner.stop();
3827
+ showComparison(currentCode, submission.code, "Your Solution", `Submission #${submissionId}`, options.unified ?? false);
3828
+ return;
3829
+ }
3830
+ const submissions = await leetcodeClient.getSubmissionList(problem.titleSlug, 50);
3831
+ const accepted = submissions.find((s) => s.statusDisplay === "Accepted");
3832
+ if (!accepted) {
3833
+ spinner.fail("No accepted submissions found for this problem");
3834
+ console.log(chalk24.gray("Tip: Use --file to compare with a local file instead"));
3835
+ return;
3836
+ }
3837
+ const acceptedDetails = await leetcodeClient.getSubmissionDetails(parseInt(accepted.id, 10));
3838
+ spinner.stop();
3839
+ showComparison(currentCode, acceptedDetails.code, "Your Solution", "Last Accepted", options.unified ?? false);
3840
+ } catch (error) {
3841
+ spinner.fail("Failed to diff");
3842
+ if (error instanceof Error) {
3843
+ console.log(chalk24.red(error.message));
3844
+ }
3845
+ }
3846
+ }
3847
+
3848
+ // src/commands/workspace.ts
3849
+ import chalk25 from "chalk";
3850
+ import inquirer4 from "inquirer";
3851
+ import { homedir as homedir3 } from "os";
3852
+ import { join as join9 } from "path";
3853
+ async function workspaceCurrentCommand() {
3854
+ const active = workspaceStorage.getActive();
3855
+ const config2 = workspaceStorage.getConfig(active);
3856
+ console.log();
3857
+ console.log(chalk25.bold.cyan(`\u{1F4C1} Active Workspace: ${active}`));
3858
+ console.log(chalk25.gray("\u2500".repeat(40)));
3859
+ console.log(` workDir: ${chalk25.white(config2.workDir)}`);
3860
+ console.log(` lang: ${chalk25.white(config2.lang)}`);
3861
+ if (config2.editor) console.log(` editor: ${chalk25.white(config2.editor)}`);
3862
+ if (config2.syncRepo) console.log(` syncRepo: ${chalk25.white(config2.syncRepo)}`);
2976
3863
  console.log();
2977
3864
  }
3865
+ async function workspaceListCommand() {
3866
+ const workspaces = workspaceStorage.list();
3867
+ const active = workspaceStorage.getActive();
3868
+ console.log();
3869
+ console.log(chalk25.bold("Workspaces:"));
3870
+ console.log();
3871
+ for (const ws of workspaces) {
3872
+ const config2 = workspaceStorage.getConfig(ws);
3873
+ const marker = ws === active ? chalk25.green("\u25B8 ") : " ";
3874
+ const name = ws === active ? chalk25.green.bold(ws) : ws;
3875
+ console.log(`${marker}${name}`);
3876
+ console.log(` ${chalk25.gray(config2.workDir)}`);
3877
+ }
3878
+ console.log();
3879
+ }
3880
+ async function workspaceCreateCommand(name, options) {
3881
+ if (workspaceStorage.exists(name)) {
3882
+ console.log(chalk25.red(`Workspace "${name}" already exists`));
3883
+ return;
3884
+ }
3885
+ const workDir = options.workdir ?? join9(homedir3(), "leetcode", name);
3886
+ const config2 = {
3887
+ workDir,
3888
+ lang: "typescript"
3889
+ };
3890
+ const success = workspaceStorage.create(name, config2);
3891
+ if (success) {
3892
+ console.log(chalk25.green(`\u2713 Created workspace "${name}"`));
3893
+ console.log(` workDir: ${chalk25.gray(workDir)}`);
3894
+ console.log();
3895
+ console.log(chalk25.gray(`Switch to it: leetcode workspace use ${name}`));
3896
+ } else {
3897
+ console.log(chalk25.red("Failed to create workspace"));
3898
+ }
3899
+ }
3900
+ async function workspaceUseCommand(name) {
3901
+ if (!workspaceStorage.exists(name)) {
3902
+ console.log(chalk25.red(`Workspace "${name}" not found`));
3903
+ console.log(chalk25.gray("Use `leetcode workspace list` to see available workspaces"));
3904
+ return;
3905
+ }
3906
+ const success = workspaceStorage.setActive(name);
3907
+ if (success) {
3908
+ const config2 = workspaceStorage.getConfig(name);
3909
+ console.log(chalk25.green(`\u2713 Switched to workspace "${name}"`));
3910
+ console.log(` workDir: ${chalk25.gray(config2.workDir)}`);
3911
+ } else {
3912
+ console.log(chalk25.red("Failed to switch workspace"));
3913
+ }
3914
+ }
3915
+ async function workspaceDeleteCommand(name) {
3916
+ if (name === "default") {
3917
+ console.log(chalk25.red("Cannot delete the default workspace"));
3918
+ return;
3919
+ }
3920
+ if (!workspaceStorage.exists(name)) {
3921
+ console.log(chalk25.red(`Workspace "${name}" not found`));
3922
+ return;
3923
+ }
3924
+ const { confirmed } = await inquirer4.prompt([{
3925
+ type: "confirm",
3926
+ name: "confirmed",
3927
+ message: `Delete workspace "${name}"? (files in workDir will NOT be deleted)`,
3928
+ default: false
3929
+ }]);
3930
+ if (!confirmed) {
3931
+ console.log(chalk25.gray("Cancelled"));
3932
+ return;
3933
+ }
3934
+ const success = workspaceStorage.delete(name);
3935
+ if (success) {
3936
+ console.log(chalk25.green(`\u2713 Deleted workspace "${name}"`));
3937
+ } else {
3938
+ console.log(chalk25.red("Failed to delete workspace"));
3939
+ }
3940
+ }
2978
3941
 
2979
3942
  // src/index.ts
2980
3943
  var program = new Command();
2981
3944
  program.configureHelp({
2982
3945
  sortSubcommands: true,
2983
- subcommandTerm: (cmd) => chalk22.cyan(cmd.name()) + (cmd.alias() ? chalk22.gray(`|${cmd.alias()}`) : ""),
2984
- subcommandDescription: (cmd) => chalk22.white(cmd.description()),
2985
- optionTerm: (option) => chalk22.yellow(option.flags),
2986
- optionDescription: (option) => chalk22.white(option.description)
3946
+ subcommandTerm: (cmd) => {
3947
+ const name = cmd.name();
3948
+ const alias = cmd.alias();
3949
+ const term = alias ? `${name}|${alias}` : name;
3950
+ return chalk26.cyan(term.padEnd(16));
3951
+ },
3952
+ subcommandDescription: (cmd) => chalk26.white(cmd.description()),
3953
+ optionTerm: (option) => chalk26.yellow(option.flags),
3954
+ optionDescription: (option) => chalk26.white(option.description)
2987
3955
  });
2988
- program.name("leetcode").usage("[command] [options]").description(chalk22.bold.cyan("\u{1F525} A modern LeetCode CLI built with TypeScript")).version("1.6.0", "-v, --version", "Output the version number").helpOption("-h, --help", "Display help for command").addHelpText("after", `
2989
- ${chalk22.yellow("Examples:")}
2990
- ${chalk22.cyan("$ leetcode login")} Login to LeetCode
2991
- ${chalk22.cyan("$ leetcode list -d easy")} List easy problems
2992
- ${chalk22.cyan("$ leetcode random -d medium")} Get random medium problem
2993
- ${chalk22.cyan("$ leetcode pick 1")} Start solving "Two Sum"
2994
- ${chalk22.cyan("$ leetcode test 1")} Test your solution
2995
- ${chalk22.cyan("$ leetcode submit 1")} Submit your solution
3956
+ program.name("leetcode").usage("[command] [options]").description(chalk26.bold.cyan("\u{1F525} A modern LeetCode CLI built with TypeScript")).version("2.0.0", "-v, --version", "Output the version number").helpOption("-h, --help", "Display help for command").addHelpText("after", `
3957
+ ${chalk26.yellow("Examples:")}
3958
+ ${chalk26.cyan("$ leetcode login")} Login to LeetCode
3959
+ ${chalk26.cyan("$ leetcode list -d easy")} List easy problems
3960
+ ${chalk26.cyan("$ leetcode random -d medium")} Get random medium problem
3961
+ ${chalk26.cyan("$ leetcode pick 1")} Start solving "Two Sum"
3962
+ ${chalk26.cyan("$ leetcode test 1")} Test your solution
3963
+ ${chalk26.cyan("$ leetcode submit 1")} Submit your solution
2996
3964
  `);
2997
3965
  program.command("login").description("Login to LeetCode with browser cookies").addHelpText("after", `
2998
- ${chalk22.yellow("How to login:")}
2999
- 1. Open ${chalk22.cyan("https://leetcode.com")} in your browser
3966
+ ${chalk26.yellow("How to login:")}
3967
+ 1. Open ${chalk26.cyan("https://leetcode.com")} in your browser
3000
3968
  2. Login to your account
3001
3969
  3. Open Developer Tools (F12) \u2192 Application \u2192 Cookies
3002
- 4. Copy values of ${chalk22.green("LEETCODE_SESSION")} and ${chalk22.green("csrftoken")}
3970
+ 4. Copy values of ${chalk26.green("LEETCODE_SESSION")} and ${chalk26.green("csrftoken")}
3003
3971
  5. Paste when prompted by this command
3004
3972
  `).action(loginCommand);
3005
3973
  program.command("logout").description("Clear stored credentials").action(logoutCommand);
3006
3974
  program.command("whoami").description("Check current login status").action(whoamiCommand);
3007
3975
  program.command("list").alias("l").description("List LeetCode problems").option("-d, --difficulty <level>", "Filter by difficulty (easy/medium/hard)").option("-s, --status <status>", "Filter by status (todo/solved/attempted)").option("-t, --tag <tags...>", "Filter by topic tags").option("-q, --search <keywords>", "Search by keywords").option("-n, --limit <number>", "Number of problems to show", "20").option("-p, --page <number>", "Page number", "1").addHelpText("after", `
3008
- ${chalk22.yellow("Examples:")}
3009
- ${chalk22.cyan("$ leetcode list")} List first 20 problems
3010
- ${chalk22.cyan("$ leetcode list -d easy")} List easy problems only
3011
- ${chalk22.cyan("$ leetcode list -s solved")} List your solved problems
3012
- ${chalk22.cyan("$ leetcode list -t array -t string")} Filter by multiple tags
3013
- ${chalk22.cyan('$ leetcode list -q "two sum"')} Search by keywords
3014
- ${chalk22.cyan("$ leetcode list -n 50 -p 2")} Show 50 problems, page 2
3976
+ ${chalk26.yellow("Examples:")}
3977
+ ${chalk26.cyan("$ leetcode list")} List first 20 problems
3978
+ ${chalk26.cyan("$ leetcode list -d easy")} List easy problems only
3979
+ ${chalk26.cyan("$ leetcode list -s solved")} List your solved problems
3980
+ ${chalk26.cyan("$ leetcode list -t array -t string")} Filter by multiple tags
3981
+ ${chalk26.cyan('$ leetcode list -q "two sum"')} Search by keywords
3982
+ ${chalk26.cyan("$ leetcode list -n 50 -p 2")} Show 50 problems, page 2
3015
3983
  `).action(listCommand);
3016
3984
  program.command("show <id>").alias("s").description("Show problem description").addHelpText("after", `
3017
- ${chalk22.yellow("Examples:")}
3018
- ${chalk22.cyan("$ leetcode show 1")} Show by problem ID
3019
- ${chalk22.cyan("$ leetcode show two-sum")} Show by problem slug
3020
- ${chalk22.cyan("$ leetcode s 412")} Short alias
3985
+ ${chalk26.yellow("Examples:")}
3986
+ ${chalk26.cyan("$ leetcode show 1")} Show by problem ID
3987
+ ${chalk26.cyan("$ leetcode show two-sum")} Show by problem slug
3988
+ ${chalk26.cyan("$ leetcode s 412")} Short alias
3021
3989
  `).action(showCommand);
3022
3990
  program.command("daily").alias("d").description("Show today's daily challenge").addHelpText("after", `
3023
- ${chalk22.yellow("Examples:")}
3024
- ${chalk22.cyan("$ leetcode daily")} Show today's challenge
3025
- ${chalk22.cyan("$ leetcode d")} Short alias
3991
+ ${chalk26.yellow("Examples:")}
3992
+ ${chalk26.cyan("$ leetcode daily")} Show today's challenge
3993
+ ${chalk26.cyan("$ leetcode d")} Short alias
3026
3994
  `).action(dailyCommand);
3027
3995
  program.command("random").alias("r").description("Get a random problem").option("-d, --difficulty <level>", "Filter by difficulty (easy/medium/hard)").option("-t, --tag <tag>", "Filter by topic tag").option("--pick", "Auto-generate solution file").option("--no-open", "Do not open file in editor").addHelpText("after", `
3028
- ${chalk22.yellow("Examples:")}
3029
- ${chalk22.cyan("$ leetcode random")} Get any random problem
3030
- ${chalk22.cyan("$ leetcode random -d medium")} Random medium problem
3031
- ${chalk22.cyan("$ leetcode random -t array")} Random array problem
3032
- ${chalk22.cyan("$ leetcode random --pick")} Random + create file
3033
- ${chalk22.cyan("$ leetcode r -d easy --pick")} Random easy + file
3996
+ ${chalk26.yellow("Examples:")}
3997
+ ${chalk26.cyan("$ leetcode random")} Get any random problem
3998
+ ${chalk26.cyan("$ leetcode random -d medium")} Random medium problem
3999
+ ${chalk26.cyan("$ leetcode random -t array")} Random array problem
4000
+ ${chalk26.cyan("$ leetcode random --pick")} Random + create file
4001
+ ${chalk26.cyan("$ leetcode r -d easy --pick")} Random easy + file
3034
4002
  `).action(randomCommand);
3035
4003
  program.command("pick <id>").alias("p").description("Generate solution file for a problem").option("-l, --lang <language>", "Programming language for the solution").option("--no-open", "Do not open file in editor").addHelpText("after", `
3036
- ${chalk22.yellow("Examples:")}
3037
- ${chalk22.cyan("$ leetcode pick 1")} Pick by problem ID
3038
- ${chalk22.cyan("$ leetcode pick two-sum")} Pick by problem slug
3039
- ${chalk22.cyan("$ leetcode pick 1 -l python3")} Pick with specific language
3040
- ${chalk22.cyan("$ leetcode pick 1 --no-open")} Create file without opening
3041
- ${chalk22.cyan("$ leetcode p 412")} Short alias
3042
-
3043
- ${chalk22.gray("Files are organized by: workDir/Difficulty/Category/")}
4004
+ ${chalk26.yellow("Examples:")}
4005
+ ${chalk26.cyan("$ leetcode pick 1")} Pick by problem ID
4006
+ ${chalk26.cyan("$ leetcode pick two-sum")} Pick by problem slug
4007
+ ${chalk26.cyan("$ leetcode pick 1 -l python3")} Pick with specific language
4008
+ ${chalk26.cyan("$ leetcode pick 1 --no-open")} Create file without opening
4009
+ ${chalk26.cyan("$ leetcode p 412")} Short alias
4010
+
4011
+ ${chalk26.gray("Files are organized by: workDir/Difficulty/Category/")}
3044
4012
  `).action(async (id, options) => {
3045
4013
  await pickCommand(id, options);
3046
4014
  });
3047
4015
  program.command("pick-batch <ids...>").description("Generate solution files for multiple problems").option("-l, --lang <language>", "Programming language for the solutions").addHelpText("after", `
3048
- ${chalk22.yellow("Examples:")}
3049
- ${chalk22.cyan("$ leetcode pick-batch 1 2 3")} Pick problems 1, 2, and 3
3050
- ${chalk22.cyan("$ leetcode pick-batch 1 2 3 -l py")} Pick with Python
4016
+ ${chalk26.yellow("Examples:")}
4017
+ ${chalk26.cyan("$ leetcode pick-batch 1 2 3")} Pick problems 1, 2, and 3
4018
+ ${chalk26.cyan("$ leetcode pick-batch 1 2 3 -l py")} Pick with Python
3051
4019
  `).action(batchPickCommand);
3052
- program.command("test <file>").alias("t").description("Test solution against sample test cases").option("-c, --testcase <testcase>", "Custom test case").addHelpText("after", `
3053
- ${chalk22.yellow("Examples:")}
3054
- ${chalk22.cyan("$ leetcode test 1")} Test by problem ID
3055
- ${chalk22.cyan("$ leetcode test two-sum")} Test by problem slug
3056
- ${chalk22.cyan("$ leetcode test ./path/to/file.py")} Test by file path
3057
- ${chalk22.cyan('$ leetcode test 1 -c "[1,2]\\n3"')} Test with custom case
3058
- ${chalk22.cyan("$ leetcode t 412")} Short alias
3059
-
3060
- ${chalk22.gray("Testcases use \\n to separate multiple inputs.")}
4020
+ program.command("test <file>").alias("t").description("Test solution against sample test cases").option("-c, --testcase <testcase>", "Custom test case").option("-V, --visualize", "Visual output for data structures (arrays, trees, etc.)").addHelpText("after", `
4021
+ ${chalk26.yellow("Examples:")}
4022
+ ${chalk26.cyan("$ leetcode test 1")} Test by problem ID
4023
+ ${chalk26.cyan("$ leetcode test two-sum")} Test by problem slug
4024
+ ${chalk26.cyan("$ leetcode test ./path/to/file.py")} Test by file path
4025
+ ${chalk26.cyan('$ leetcode test 1 -c "[1,2]\\n3"')} Test with custom case
4026
+ ${chalk26.cyan("$ leetcode test 1 --visualize")} Visual mode for debugging
4027
+ ${chalk26.cyan("$ leetcode t 412")} Short alias
4028
+
4029
+ ${chalk26.gray("Testcases use \\n to separate multiple inputs.")}
3061
4030
  `).action(testCommand);
3062
4031
  program.command("submit <file>").alias("x").description("Submit solution to LeetCode").addHelpText("after", `
3063
- ${chalk22.yellow("Examples:")}
3064
- ${chalk22.cyan("$ leetcode submit 1")} Submit by problem ID
3065
- ${chalk22.cyan("$ leetcode submit two-sum")} Submit by problem slug
3066
- ${chalk22.cyan("$ leetcode submit ./path/to/file.py")} Submit by file path
3067
- ${chalk22.cyan("$ leetcode x 412")} Short alias
4032
+ ${chalk26.yellow("Examples:")}
4033
+ ${chalk26.cyan("$ leetcode submit 1")} Submit by problem ID
4034
+ ${chalk26.cyan("$ leetcode submit two-sum")} Submit by problem slug
4035
+ ${chalk26.cyan("$ leetcode submit ./path/to/file.py")} Submit by file path
4036
+ ${chalk26.cyan("$ leetcode x 412")} Short alias
3068
4037
  `).action(submitCommand);
4038
+ program.command("diff <id>").description("Compare solution with past submissions").option("-s, --submission <id>", "Compare with specific submission ID").option("-f, --file <path>", "Compare with a local file").option("-u, --unified", "Show unified diff (line-by-line changes)").addHelpText("after", `
4039
+ ${chalk26.yellow("Examples:")}
4040
+ ${chalk26.cyan("$ leetcode diff 1")} Compare with last accepted
4041
+ ${chalk26.cyan("$ leetcode diff 1 -u")} Show unified diff
4042
+ ${chalk26.cyan("$ leetcode diff 1 -s 12345")} Compare with specific submission
4043
+ ${chalk26.cyan("$ leetcode diff 1 -f other.py")} Compare with local file
4044
+ `).action(diffCommand);
3069
4045
  program.command("submissions <id>").description("View past submissions").option("-n, --limit <number>", "Number of submissions to show", "20").option("--last", "Show details of the last accepted submission").option("--download", "Download the last accepted submission code").addHelpText("after", `
3070
- ${chalk22.yellow("Examples:")}
3071
- ${chalk22.cyan("$ leetcode submissions 1")} View submissions for problem
3072
- ${chalk22.cyan("$ leetcode submissions 1 -n 5")} Show last 5 submissions
3073
- ${chalk22.cyan("$ leetcode submissions 1 --last")} Show last accepted submission
3074
- ${chalk22.cyan("$ leetcode submissions 1 --download")} Download last accepted code
4046
+ ${chalk26.yellow("Examples:")}
4047
+ ${chalk26.cyan("$ leetcode submissions 1")} View submissions for problem
4048
+ ${chalk26.cyan("$ leetcode submissions 1 -n 5")} Show last 5 submissions
4049
+ ${chalk26.cyan("$ leetcode submissions 1 --last")} Show last accepted submission
4050
+ ${chalk26.cyan("$ leetcode submissions 1 --download")} Download last accepted code
3075
4051
  `).action(submissionsCommand);
3076
4052
  program.command("stat [username]").description("Show user statistics and analytics").option("-c, --calendar", "Weekly activity summary (submissions & active days for last 12 weeks)").option("-s, --skills", "Skill breakdown (problems solved grouped by topic tags)").option("-t, --trend", "Daily trend chart (bar graph of submissions for last 7 days)").addHelpText("after", `
3077
- ${chalk22.yellow("Options Explained:")}
3078
- ${chalk22.cyan("-c, --calendar")} Shows a table of your weekly submissions and active days
4053
+ ${chalk26.yellow("Options Explained:")}
4054
+ ${chalk26.cyan("-c, --calendar")} Shows a table of your weekly submissions and active days
3079
4055
  for the past 12 weeks. Useful for tracking consistency.
3080
4056
 
3081
- ${chalk22.cyan("-s, --skills")} Shows how many problems you solved per topic tag,
4057
+ ${chalk26.cyan("-s, --skills")} Shows how many problems you solved per topic tag,
3082
4058
  grouped by difficulty (Fundamental/Intermediate/Advanced).
3083
4059
  Helps identify your strong and weak areas.
3084
4060
 
3085
- ${chalk22.cyan("-t, --trend")} Shows a bar chart of daily submissions for the past week.
4061
+ ${chalk26.cyan("-t, --trend")} Shows a bar chart of daily submissions for the past week.
3086
4062
  Visualizes your recent coding activity day by day.
3087
4063
 
3088
- ${chalk22.yellow("Examples:")}
3089
- ${chalk22.cyan("$ leetcode stat")} Show basic stats (solved count, rank)
3090
- ${chalk22.cyan("$ leetcode stat lee215")} Show another user's stats
3091
- ${chalk22.cyan("$ leetcode stat -c")} Weekly activity table
3092
- ${chalk22.cyan("$ leetcode stat -s")} Topic-wise breakdown
3093
- ${chalk22.cyan("$ leetcode stat -t")} 7-day trend chart
4064
+ ${chalk26.yellow("Examples:")}
4065
+ ${chalk26.cyan("$ leetcode stat")} Show basic stats (solved count, rank)
4066
+ ${chalk26.cyan("$ leetcode stat lee215")} Show another user's stats
4067
+ ${chalk26.cyan("$ leetcode stat -c")} Weekly activity table
4068
+ ${chalk26.cyan("$ leetcode stat -s")} Topic-wise breakdown
4069
+ ${chalk26.cyan("$ leetcode stat -t")} 7-day trend chart
3094
4070
  `).action((username, options) => statCommand(username, options));
3095
4071
  program.command("today").description("Show today's progress summary").addHelpText("after", `
3096
- ${chalk22.yellow("Examples:")}
3097
- ${chalk22.cyan("$ leetcode today")} Show streak, solved, and daily challenge
4072
+ ${chalk26.yellow("Examples:")}
4073
+ ${chalk26.cyan("$ leetcode today")} Show streak, solved, and daily challenge
3098
4074
  `).action(todayCommand);
3099
4075
  program.command("bookmark <action> [id]").description("Manage problem bookmarks").addHelpText("after", `
3100
- ${chalk22.yellow("Actions:")}
3101
- ${chalk22.cyan("add <id>")} Bookmark a problem
3102
- ${chalk22.cyan("remove <id>")} Remove a bookmark
3103
- ${chalk22.cyan("list")} List all bookmarks
3104
- ${chalk22.cyan("clear")} Clear all bookmarks
3105
-
3106
- ${chalk22.yellow("Examples:")}
3107
- ${chalk22.cyan("$ leetcode bookmark add 1")} Bookmark problem 1
3108
- ${chalk22.cyan("$ leetcode bookmark remove 1")} Remove bookmark
3109
- ${chalk22.cyan("$ leetcode bookmark list")} List all bookmarks
4076
+ ${chalk26.yellow("Actions:")}
4077
+ ${chalk26.cyan("add <id>")} Bookmark a problem
4078
+ ${chalk26.cyan("remove <id>")} Remove a bookmark
4079
+ ${chalk26.cyan("list")} List all bookmarks
4080
+ ${chalk26.cyan("clear")} Clear all bookmarks
4081
+
4082
+ ${chalk26.yellow("Examples:")}
4083
+ ${chalk26.cyan("$ leetcode bookmark add 1")} Bookmark problem 1
4084
+ ${chalk26.cyan("$ leetcode bookmark remove 1")} Remove bookmark
4085
+ ${chalk26.cyan("$ leetcode bookmark list")} List all bookmarks
3110
4086
  `).action(bookmarkCommand);
3111
4087
  program.command("note <id> [action]").description("View or edit notes for a problem").addHelpText("after", `
3112
- ${chalk22.yellow("Actions:")}
3113
- ${chalk22.cyan("edit")} Open notes in editor (default)
3114
- ${chalk22.cyan("view")} Display notes in terminal
3115
-
3116
- ${chalk22.yellow("Examples:")}
3117
- ${chalk22.cyan("$ leetcode note 1")} Edit notes for problem 1
3118
- ${chalk22.cyan("$ leetcode note 1 edit")} Edit notes (explicit)
3119
- ${chalk22.cyan("$ leetcode note 1 view")} View notes in terminal
4088
+ ${chalk26.yellow("Actions:")}
4089
+ ${chalk26.cyan("edit")} Open notes in editor (default)
4090
+ ${chalk26.cyan("view")} Display notes in terminal
4091
+
4092
+ ${chalk26.yellow("Examples:")}
4093
+ ${chalk26.cyan("$ leetcode note 1")} Edit notes for problem 1
4094
+ ${chalk26.cyan("$ leetcode note 1 edit")} Edit notes (explicit)
4095
+ ${chalk26.cyan("$ leetcode note 1 view")} View notes in terminal
3120
4096
  `).action(notesCommand);
3121
4097
  program.command("sync").description("Sync solutions to Git repository").addHelpText("after", `
3122
- ${chalk22.yellow("Examples:")}
3123
- ${chalk22.cyan("$ leetcode sync")} Sync all solutions to remote
4098
+ ${chalk26.yellow("Examples:")}
4099
+ ${chalk26.cyan("$ leetcode sync")} Sync all solutions to remote
3124
4100
  `).action(syncCommand);
3125
4101
  program.command("config").description("View or set configuration").option("-l, --lang <language>", "Set default programming language").option("-e, --editor <editor>", "Set editor command").option("-w, --workdir <path>", "Set working directory for solutions").option("-r, --repo <url>", "Set Git repository URL").option("-i, --interactive", "Interactive configuration").addHelpText("after", `
3126
- ${chalk22.yellow("Examples:")}
3127
- ${chalk22.cyan("$ leetcode config")} View current config
3128
- ${chalk22.cyan("$ leetcode config -l python3")} Set language to Python
3129
- ${chalk22.cyan('$ leetcode config -e "code"')} Set editor to VS Code
3130
- ${chalk22.cyan("$ leetcode config -w ~/leetcode")} Set solutions folder
3131
- ${chalk22.cyan("$ leetcode config -r https://...")} Set git repository
3132
- ${chalk22.cyan("$ leetcode config -i")} Interactive setup
3133
-
3134
- ${chalk22.gray("Supported languages: typescript, javascript, python3, java, cpp, c, csharp, go, rust, kotlin, swift")}
4102
+ ${chalk26.yellow("Examples:")}
4103
+ ${chalk26.cyan("$ leetcode config")} View current config
4104
+ ${chalk26.cyan("$ leetcode config -l python3")} Set language to Python
4105
+ ${chalk26.cyan('$ leetcode config -e "code"')} Set editor to VS Code
4106
+ ${chalk26.cyan("$ leetcode config -w ~/leetcode")} Set solutions folder
4107
+ ${chalk26.cyan("$ leetcode config -r https://...")} Set git repository
4108
+ ${chalk26.cyan("$ leetcode config -i")} Interactive setup
4109
+
4110
+ ${chalk26.gray("Supported languages: typescript, javascript, python3, java, cpp, c, csharp, go, rust, kotlin, swift")}
3135
4111
  `).action(async (options) => {
3136
4112
  if (options.interactive) {
3137
4113
  await configInteractiveCommand();
@@ -3140,31 +4116,37 @@ ${chalk22.gray("Supported languages: typescript, javascript, python3, java, cpp,
3140
4116
  }
3141
4117
  });
3142
4118
  program.command("timer [id]").description("Start interview mode with timer").option("-m, --minutes <minutes>", "Custom time limit in minutes").option("--stats", "Show solve time statistics").option("--stop", "Stop active timer").addHelpText("after", `
3143
- ${chalk22.yellow("How it works:")}
4119
+ ${chalk26.yellow("How it works:")}
3144
4120
  Start a problem with a countdown timer to simulate interview conditions.
3145
4121
  Default time limits: Easy (20 min), Medium (40 min), Hard (60 min).
3146
4122
  Your solve times are recorded when you submit successfully.
3147
4123
 
3148
- ${chalk22.yellow("Examples:")}
3149
- ${chalk22.cyan("$ leetcode timer 1")} Start problem 1 with default time
3150
- ${chalk22.cyan("$ leetcode timer 1 -m 30")} Start with 30 minute limit
3151
- ${chalk22.cyan("$ leetcode timer --stats")} Show your solve time statistics
3152
- ${chalk22.cyan("$ leetcode timer --stop")} Stop active timer
4124
+ ${chalk26.yellow("Examples:")}
4125
+ ${chalk26.cyan("$ leetcode timer 1")} Start problem 1 with default time
4126
+ ${chalk26.cyan("$ leetcode timer 1 -m 30")} Start with 30 minute limit
4127
+ ${chalk26.cyan("$ leetcode timer --stats")} Show your solve time statistics
4128
+ ${chalk26.cyan("$ leetcode timer --stop")} Stop active timer
3153
4129
  `).action((id, options) => timerCommand(id, options));
4130
+ var workspaceCmd = program.command("workspace").description("Manage workspaces for different contexts");
4131
+ workspaceCmd.command("current").description("Show current workspace").action(workspaceCurrentCommand);
4132
+ workspaceCmd.command("list").description("List all workspaces").action(workspaceListCommand);
4133
+ workspaceCmd.command("create <name>").description("Create a new workspace").option("-w, --workdir <path>", "Set working directory for this workspace").action(workspaceCreateCommand);
4134
+ workspaceCmd.command("use <name>").description("Switch to a workspace").action(workspaceUseCommand);
4135
+ workspaceCmd.command("delete <name>").description("Delete a workspace").action(workspaceDeleteCommand);
3154
4136
  var collabCmd = program.command("collab").description("Collaborative coding with a partner").addHelpText("after", `
3155
- ${chalk22.yellow("Subcommands:")}
3156
- ${chalk22.cyan("host <id>")} Create a room and get a code to share
3157
- ${chalk22.cyan("join <code>")} Join a room with the shared code
3158
- ${chalk22.cyan("sync")} Upload your solution to the room
3159
- ${chalk22.cyan("compare")} View both solutions side by side
3160
- ${chalk22.cyan("status")} Check room and sync status
3161
- ${chalk22.cyan("leave")} End the collaboration session
3162
-
3163
- ${chalk22.yellow("Examples:")}
3164
- ${chalk22.gray("$ leetcode collab host 1")} Start a session for Two Sum
3165
- ${chalk22.gray("$ leetcode collab join ABC123")} Join your partner's session
3166
- ${chalk22.gray("$ leetcode collab sync")} Upload your code after solving
3167
- ${chalk22.gray("$ leetcode collab compare")} Compare solutions
4137
+ ${chalk26.yellow("Subcommands:")}
4138
+ ${chalk26.cyan("host <id>")} Create a room and get a code to share
4139
+ ${chalk26.cyan("join <code>")} Join a room with the shared code
4140
+ ${chalk26.cyan("sync")} Upload your solution to the room
4141
+ ${chalk26.cyan("compare")} View both solutions side by side
4142
+ ${chalk26.cyan("status")} Check room and sync status
4143
+ ${chalk26.cyan("leave")} End the collaboration session
4144
+
4145
+ ${chalk26.yellow("Examples:")}
4146
+ ${chalk26.gray("$ leetcode collab host 1")} Start a session for Two Sum
4147
+ ${chalk26.gray("$ leetcode collab join ABC123")} Join your partner's session
4148
+ ${chalk26.gray("$ leetcode collab sync")} Upload your code after solving
4149
+ ${chalk26.gray("$ leetcode collab compare")} Compare solutions
3168
4150
  `);
3169
4151
  collabCmd.command("host <problemId>").description("Host a collaboration session").action(collabHostCommand);
3170
4152
  collabCmd.command("join <roomCode>").description("Join a collaboration session").action(collabJoinCommand);
@@ -3172,12 +4154,31 @@ collabCmd.command("sync").description("Sync your code with partner").action(coll
3172
4154
  collabCmd.command("compare").description("Compare your solution with partner").action(collabCompareCommand);
3173
4155
  collabCmd.command("leave").description("Leave the collaboration session").action(collabLeaveCommand);
3174
4156
  collabCmd.command("status").description("Show collaboration status").action(collabStatusCommand);
4157
+ var snapshotCmd = program.command("snapshot").description("Save and restore solution versions").addHelpText("after", `
4158
+ ${chalk26.yellow("Subcommands:")}
4159
+ ${chalk26.cyan("save <id> [name]")} Save current solution as a snapshot
4160
+ ${chalk26.cyan("list <id>")} List all snapshots for a problem
4161
+ ${chalk26.cyan("restore <id> <snapshot>")} Restore a snapshot
4162
+ ${chalk26.cyan("diff <id> <s1> <s2>")} Compare two snapshots
4163
+ ${chalk26.cyan("delete <id> <snapshot>")} Delete a snapshot
4164
+
4165
+ ${chalk26.yellow("Examples:")}
4166
+ ${chalk26.gray('$ leetcode snapshot save 1 "brute-force"')} Save current solution
4167
+ ${chalk26.gray("$ leetcode snapshot list 1")} List snapshots
4168
+ ${chalk26.gray("$ leetcode snapshot restore 1 2")} Restore snapshot #2
4169
+ ${chalk26.gray("$ leetcode snapshot diff 1 1 2")} Compare snapshots
4170
+ `);
4171
+ snapshotCmd.command("save <id> [name]").description("Save current solution as a snapshot").action(snapshotSaveCommand);
4172
+ snapshotCmd.command("list <id>").description("List all snapshots for a problem").action(snapshotListCommand);
4173
+ snapshotCmd.command("restore <id> <snapshot>").description("Restore a snapshot").action(snapshotRestoreCommand);
4174
+ snapshotCmd.command("diff <id> <snap1> <snap2>").description("Compare two snapshots").action(snapshotDiffCommand);
4175
+ snapshotCmd.command("delete <id> <snapshot>").description("Delete a snapshot").action(snapshotDeleteCommand);
3175
4176
  program.showHelpAfterError("(add --help for additional information)");
3176
4177
  program.parse();
3177
4178
  if (!process.argv.slice(2).length) {
3178
4179
  console.log();
3179
- console.log(chalk22.bold.cyan(" \u{1F525} LeetCode CLI"));
3180
- console.log(chalk22.gray(" A modern command-line interface for LeetCode"));
4180
+ console.log(chalk26.bold.cyan(" \u{1F525} LeetCode CLI"));
4181
+ console.log(chalk26.gray(" A modern command-line interface for LeetCode"));
3181
4182
  console.log();
3182
4183
  program.outputHelp();
3183
4184
  }