learn_bash_from_session_data 1.0.5 → 1.0.6

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.
@@ -18,6 +18,45 @@ import random
18
18
  import re
19
19
  import hashlib
20
20
 
21
+ try:
22
+ from scripts.knowledge_base import COMMAND_DB, get_command_info, get_flags_for_command
23
+ except ImportError:
24
+ try:
25
+ from knowledge_base import COMMAND_DB, get_command_info, get_flags_for_command
26
+ except ImportError:
27
+ COMMAND_DB = {}
28
+ def get_command_info(name): return None
29
+ def get_flags_for_command(command): return {}
30
+
31
+
32
+ def _get_flags_for_cmd(cmd: str) -> dict[str, str]:
33
+ """Get merged flags for a command from knowledge_base (primary) and local FLAG_DATABASE (fallback).
34
+
35
+ Knowledge_base.py COMMAND_DB is the authoritative source. FLAG_DATABASE provides
36
+ additional coverage for commands not yet in knowledge_base.
37
+ """
38
+ flags = {}
39
+ # Primary source: knowledge_base COMMAND_DB
40
+ kb_flags = get_flags_for_command(cmd)
41
+ if kb_flags:
42
+ flags.update(kb_flags)
43
+ # Fallback/supplement: local FLAG_DATABASE
44
+ if cmd in FLAG_DATABASE:
45
+ for flag, desc in FLAG_DATABASE[cmd].items():
46
+ if flag not in flags:
47
+ flags[flag] = desc
48
+ return flags
49
+
50
+
51
+ def _get_all_flagged_commands() -> set[str]:
52
+ """Get the set of all commands that have flag data from any source."""
53
+ cmds = set()
54
+ for cmd, info in COMMAND_DB.items():
55
+ if info.get("flags"):
56
+ cmds.add(cmd)
57
+ cmds.update(FLAG_DATABASE.keys())
58
+ return cmds
59
+
21
60
 
22
61
  class QuizType(Enum):
23
62
  """Types of quiz questions."""
@@ -499,6 +538,19 @@ def _describe_single_command(cmd: str) -> str:
499
538
  tokens = cmd.split()
500
539
  base_cmd = tokens[0] if tokens else ''
501
540
 
541
+ # Get args (skip flags) for knowledge_base fallback
542
+ args = [t for t in tokens[1:] if not t.startswith('-')]
543
+
544
+ # Check knowledge_base COMMAND_DB for rich description
545
+ if base_cmd and base_cmd in COMMAND_DB:
546
+ cmd_info = COMMAND_DB[base_cmd]
547
+ kb_desc = cmd_info.get('description', '')
548
+ if kb_desc:
549
+ # Use knowledge base description but make it contextual with args
550
+ if args:
551
+ return f"{kb_desc.lower()} ({' '.join(args[:2])})"
552
+ return kb_desc.lower()
553
+
502
554
  # Common command descriptions with bash focus
503
555
  descriptions = {
504
556
  'cd': lambda args: f"changes directory to {args[0] if args else 'specified path'}",
@@ -637,35 +689,35 @@ def _parse_command(cmd_string: str) -> dict:
637
689
 
638
690
 
639
691
  def _get_flag_description(cmd: str, flag: str) -> Optional[str]:
640
- """Get description for a flag of a command."""
641
- if cmd in FLAG_DATABASE:
642
- # Handle flags like -la (combined short flags)
643
- if flag in FLAG_DATABASE[cmd]:
644
- return FLAG_DATABASE[cmd][flag]
645
- # Try individual characters for combined flags
646
- if len(flag) > 2 and flag.startswith("-") and not flag.startswith("--"):
647
- for char in flag[1:]:
648
- single_flag = f"-{char}"
649
- if single_flag in FLAG_DATABASE[cmd]:
650
- return FLAG_DATABASE[cmd][single_flag]
692
+ """Get description for a flag of a command from merged sources."""
693
+ merged = _get_flags_for_cmd(cmd)
694
+ if flag in merged:
695
+ return merged[flag]
696
+ # Try individual characters for combined flags (e.g., -la -> -l, -a)
697
+ if len(flag) > 2 and flag.startswith("-") and not flag.startswith("--"):
698
+ for char in flag[1:]:
699
+ single_flag = f"-{char}"
700
+ if single_flag in merged:
701
+ return merged[single_flag]
651
702
  return None
652
703
 
653
704
 
654
705
  def _generate_distractor_flags(cmd: str, correct_flag: str, count: int = 3) -> list[str]:
655
- """Generate plausible distractor flags."""
706
+ """Generate plausible distractor flags from merged knowledge sources."""
656
707
  distractors = []
657
708
 
658
- # Get other flags from the same command
659
- if cmd in FLAG_DATABASE:
660
- other_flags = [f for f in FLAG_DATABASE[cmd].keys() if f != correct_flag]
709
+ # Get other flags from the same command (merged sources)
710
+ cmd_flags = _get_flags_for_cmd(cmd)
711
+ if cmd_flags:
712
+ other_flags = [f for f in cmd_flags.keys() if f != correct_flag]
661
713
  random.shuffle(other_flags)
662
714
  distractors.extend(other_flags[:count])
663
715
 
664
716
  # If we need more, get common flags from other commands
665
717
  if len(distractors) < count:
666
- for other_cmd, flags in FLAG_DATABASE.items():
718
+ for other_cmd in _get_all_flagged_commands():
667
719
  if other_cmd != cmd:
668
- for flag in flags:
720
+ for flag in _get_flags_for_cmd(other_cmd):
669
721
  if flag not in distractors and flag != correct_flag:
670
722
  distractors.append(flag)
671
723
  if len(distractors) >= count:
@@ -680,10 +732,10 @@ def _generate_distractor_descriptions(correct_desc: str, count: int = 3) -> list
680
732
  """Generate plausible wrong descriptions."""
681
733
  distractors = []
682
734
 
683
- # Collect all descriptions from FLAG_DATABASE
735
+ # Collect all descriptions from merged sources
684
736
  all_descriptions = []
685
- for cmd_flags in FLAG_DATABASE.values():
686
- all_descriptions.extend(cmd_flags.values())
737
+ for cmd in _get_all_flagged_commands():
738
+ all_descriptions.extend(_get_flags_for_cmd(cmd).values())
687
739
 
688
740
  # Remove duplicates and the correct answer
689
741
  all_descriptions = list(set(all_descriptions))
@@ -797,16 +849,17 @@ def generate_which_flag_quiz(
797
849
  parsed = _parse_command(cmd_string)
798
850
  base_cmd = parsed["base"]
799
851
 
800
- if base_cmd not in FLAG_DATABASE or not parsed["flags"]:
852
+ cmd_flags = _get_flags_for_cmd(base_cmd)
853
+ if not cmd_flags or not parsed["flags"]:
801
854
  return None
802
855
 
803
856
  # Pick a flag to quiz on
804
- available_flags = [f for f in parsed["flags"] if f in FLAG_DATABASE.get(base_cmd, {})]
857
+ available_flags = [f for f in parsed["flags"] if f in cmd_flags]
805
858
  if not available_flags:
806
859
  return None
807
860
 
808
861
  target_flag = random.choice(available_flags)
809
- flag_desc = FLAG_DATABASE[base_cmd][target_flag]
862
+ flag_desc = cmd_flags[target_flag]
810
863
 
811
864
  # Generate distractor flags
812
865
  distractor_flags = _generate_distractor_flags(base_cmd, target_flag, 3)
@@ -831,13 +884,13 @@ def generate_which_flag_quiz(
831
884
  correct_id = opt_id
832
885
 
833
886
  # Get description for option explanation
834
- flag_explanation = FLAG_DATABASE.get(base_cmd, {}).get(flag, "Unknown flag")
887
+ flag_explanation = cmd_flags.get(flag, "Unknown flag")
835
888
 
836
889
  options.append(QuizOption(
837
890
  id=opt_id,
838
891
  text=flag,
839
892
  is_correct=is_correct,
840
- explanation=f"{flag}: {flag_explanation}" if flag in FLAG_DATABASE.get(base_cmd, {}) else f"{flag}: Not a standard flag for {base_cmd}"
893
+ explanation=f"{flag}: {flag_explanation}" if flag in cmd_flags else f"{flag}: Not a standard flag for {base_cmd}"
841
894
  ))
842
895
 
843
896
  question_id = _generate_id(f"which_flag_{base_cmd}_{target_flag}")
@@ -896,7 +949,7 @@ def generate_build_command_quiz(
896
949
  distractors.append(" ".join(missing_flag))
897
950
 
898
951
  # Distractor 3: Wrong flag
899
- if parsed["flags"] and base_cmd in FLAG_DATABASE:
952
+ if parsed["flags"] and _get_flags_for_cmd(base_cmd):
900
953
  wrong_flags = _generate_distractor_flags(base_cmd, parsed["flags"][0], 1)
901
954
  if wrong_flags:
902
955
  wrong_flag_cmd = [base_cmd] + [wrong_flags[0]] + parsed["flags"][1:] + parsed["args"]
@@ -1065,14 +1118,15 @@ def _create_similar_command_variant(command: dict) -> Optional[dict]:
1065
1118
  parsed = _parse_command(cmd_string)
1066
1119
  base_cmd = parsed["base"]
1067
1120
 
1068
- if base_cmd not in FLAG_DATABASE:
1121
+ variant_flags = _get_flags_for_cmd(base_cmd)
1122
+ if not variant_flags:
1069
1123
  return None
1070
1124
 
1071
1125
  # Strategy: add, remove, or change a flag
1072
1126
  strategies = []
1073
1127
 
1074
1128
  # Can add a flag
1075
- available_flags = [f for f in FLAG_DATABASE[base_cmd].keys() if f not in parsed["flags"]]
1129
+ available_flags = [f for f in variant_flags.keys() if f not in parsed["flags"]]
1076
1130
  if available_flags:
1077
1131
  strategies.append("add")
1078
1132
 
package/vectors.db ADDED
Binary file