learn_bash_from_session_data 1.0.10 → 1.1.1

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.
@@ -158,6 +158,7 @@ def render_overview_tab(stats: dict[str, Any], commands: list[dict], categories:
158
158
  unique_commands = stats.get("unique_commands", 0)
159
159
  unique_utilities = stats.get("unique_utilities", 0)
160
160
  date_range = stats.get("date_range", {"start": "N/A", "end": "N/A"})
161
+
161
162
  # Get operators data for the "Bash Operators Used" section
162
163
  operators_used = stats.get("operators_used", {})
163
164
  operator_descriptions = {
@@ -312,6 +313,7 @@ def render_overview_tab(stats: dict[str, Any], commands: list[dict], categories:
312
313
  </div>
313
314
  </div>
314
315
  </div>
316
+
315
317
  </div>'''
316
318
 
317
319
 
@@ -425,12 +427,44 @@ def render_commands_tab(commands: list[dict]) -> str:
425
427
  <pre class="output-preview">{html.escape(output_preview)}</pre>
426
428
  </div>'''
427
429
 
430
+ # Use cases from knowledge base
431
+ use_cases = cmd.get("use_cases", [])
432
+ use_cases_html = ""
433
+ if use_cases:
434
+ use_cases_html = '<div class="use-cases-section"><h5>Use Cases:</h5><ul class="use-cases-list">'
435
+ for uc in use_cases[:3]:
436
+ use_cases_html += f'<li>{html.escape(uc)}</li>'
437
+ use_cases_html += '</ul></div>'
438
+
439
+ # Gotchas / pitfalls from knowledge base
440
+ gotchas = cmd.get("gotchas", [])
441
+ gotchas_html = ""
442
+ if gotchas:
443
+ gotchas_html = '<div class="gotchas-section"><h5>Common Pitfalls:</h5><ul class="gotchas-list">'
444
+ for g in gotchas[:2]:
445
+ gotchas_html += f'<li>{html.escape(g)}</li>'
446
+ gotchas_html += '</ul></div>'
447
+
448
+ # Related commands
449
+ related = cmd.get("related", [])
450
+ related_html = ""
451
+ if related:
452
+ related_chips = ' '.join(f'<code class="related-cmd">{html.escape(r)}</code>' for r in related[:5])
453
+ related_html = f'<div class="related-section"><h5>Related:</h5> {related_chips}</div>'
454
+
455
+ # Man page / documentation link
456
+ man_url = cmd.get("man_url", "")
457
+ man_link_html = ""
458
+ if man_url:
459
+ man_link_html = f'<a class="man-link" href="{html.escape(man_url)}" target="_blank" rel="noopener noreferrer" title="Documentation">docs</a>'
460
+
428
461
  commands_html += f'''
429
462
  <div class="command-card" data-category="{category}" data-frequency="{frequency}" data-name="{base_cmd}">
430
463
  <div class="command-header" onclick="toggleCommand('{cmd_id}')">
431
464
  <div class="command-main">
432
465
  <code class="cmd">{base_cmd}</code>
433
466
  <span class="category-badge">{category}</span>
467
+ {man_link_html}
434
468
  </div>
435
469
  <div class="command-meta">
436
470
  <span class="cmd-preview">{' '.join(description.split())[:60]}{'...' if len(' '.join(description.split())) > 60 else ''}</span>
@@ -448,7 +482,10 @@ def render_commands_tab(commands: list[dict]) -> str:
448
482
  </div>
449
483
  {subcmd_html}
450
484
  {flags_html}
485
+ {use_cases_html}
486
+ {gotchas_html}
451
487
  {patterns_html}
488
+ {related_html}
452
489
  {output_html}
453
490
  </div>
454
491
  </div>'''
@@ -563,16 +600,38 @@ def render_lessons_tab(categories: dict, commands: list[dict]) -> str:
563
600
  if subcmd_desc:
564
601
  lesson_subcmd = f'<div class="lesson-subcmd"><em>{html.escape(subcmd_desc)}</em></div>'
565
602
 
603
+ # Use cases and gotchas from COMMAND_DB for lessons
604
+ lesson_use_cases = ""
605
+ cmd_db_info = COMMAND_DB.get(base_cmd.replace("&amp;", "&"), {})
606
+ uc_list = cmd_db_info.get("use_cases", [])
607
+ if uc_list:
608
+ uc_items = ''.join(f'<li>{html.escape(uc)}</li>' for uc in uc_list[:2])
609
+ lesson_use_cases = f'<div class="lesson-use-cases"><strong>When to use:</strong><ul>{uc_items}</ul></div>'
610
+
611
+ lesson_gotchas = ""
612
+ gotcha_list = cmd_db_info.get("gotchas", [])
613
+ if gotcha_list:
614
+ g_items = ''.join(f'<li>{html.escape(g)}</li>' for g in gotcha_list[:1])
615
+ lesson_gotchas = f'<div class="lesson-gotchas"><strong>Watch out:</strong><ul>{g_items}</ul></div>'
616
+
617
+ lesson_man_url = ""
618
+ man_link = cmd_db_info.get("man_url", "")
619
+ if man_link:
620
+ lesson_man_url = f'<a class="man-link" href="{html.escape(man_link)}" target="_blank" rel="noopener noreferrer">docs</a>'
621
+
566
622
  cat_commands_html += f'''
567
623
  <div class="lesson-command">
568
624
  <div class="lesson-command-header">
569
625
  <code class="cmd">{base_cmd}</code>
570
626
  <span class="lesson-complexity complexity-{complexity}">{complexity}</span>
627
+ {lesson_man_url}
571
628
  </div>
572
629
  <pre class="syntax-highlighted">{highlighted}</pre>
573
630
  <p class="lesson-description">{description}</p>
574
631
  {lesson_subcmd}
575
632
  {lesson_flags_html}
633
+ {lesson_use_cases}
634
+ {lesson_gotchas}
576
635
  </div>'''
577
636
 
578
637
  # Patterns observed
@@ -584,6 +643,23 @@ def render_lessons_tab(categories: dict, commands: list[dict]) -> str:
584
643
  patterns_html += f'<li>{html.escape(pattern)}</li>'
585
644
  patterns_html += '</ul></div>'
586
645
 
646
+ # Collect related commands across this category for cross-reference
647
+ related_set = set()
648
+ cat_base_cmds = {c.get("base_command", "") for c in cat_cmd_data}
649
+ for cmd_item in cat_cmd_data:
650
+ bc = cmd_item.get("base_command", "").replace("&amp;", "&")
651
+ cmd_db_info = COMMAND_DB.get(bc, {})
652
+ for rel in cmd_db_info.get("related", []):
653
+ if rel not in cat_base_cmds:
654
+ related_set.add(rel)
655
+ related_html = ""
656
+ if related_set:
657
+ related_chips = ' '.join(
658
+ f'<code class="related-cmd">{html.escape(r)}</code>'
659
+ for r in sorted(related_set)[:12]
660
+ )
661
+ related_html = f'<div class="lesson-related-section"><h4>Explore Related Commands:</h4><div class="related-chips">{related_chips}</div></div>'
662
+
587
663
  lessons_html += f'''
588
664
  <div class="lesson-section">
589
665
  <h2 class="lesson-title">
@@ -601,6 +677,7 @@ def render_lessons_tab(categories: dict, commands: list[dict]) -> str:
601
677
  {cat_commands_html}
602
678
  </div>
603
679
  {patterns_html}
680
+ {related_html}
604
681
  </div>
605
682
  </div>'''
606
683
 
@@ -696,6 +773,12 @@ def render_quiz_tab(quizzes: list[dict]) -> str:
696
773
  options = quiz.get("options", [])
697
774
  correct = quiz.get("correct_answer", 0)
698
775
  explanation = html.escape(quiz.get("explanation", ""))
776
+ q_man_url = quiz.get("man_url", "")
777
+
778
+ # Doc link for quiz context
779
+ q_meta_html = ""
780
+ if q_man_url:
781
+ q_meta_html = f'<div class="quiz-meta"><a class="man-link" href="{html.escape(q_man_url)}" target="_blank" rel="noopener noreferrer">docs</a></div>'
699
782
 
700
783
  options_html = ""
701
784
  for opt_idx, option in enumerate(options):
@@ -709,7 +792,10 @@ def render_quiz_tab(quizzes: list[dict]) -> str:
709
792
 
710
793
  questions_html += f'''
711
794
  <div class="quiz-question" id="question-{q_id}">
712
- <div class="question-number">Question {idx + 1}</div>
795
+ <div class="question-header">
796
+ <div class="question-number">Question {idx + 1}</div>
797
+ {q_meta_html}
798
+ </div>
713
799
  <div class="question-text">{question}</div>
714
800
  <div class="quiz-options">
715
801
  {options_html}
@@ -859,6 +945,17 @@ def get_inline_css() -> str:
859
945
  .dark-icon { display: none; }
860
946
  [data-theme="dark"] .light-icon { display: none; }
861
947
  [data-theme="dark"] .dark-icon { display: inline; }
948
+ [data-theme="dark"] .gotchas-section,
949
+ [data-theme="dark"] .lesson-gotchas { background: #3e2723; border-left-color: #ff8f00; }
950
+ [data-theme="dark"] .gotchas-list li,
951
+ [data-theme="dark"] .lesson-gotchas li { color: #ffcc80; }
952
+ [data-theme="dark"] .gotchas-section h5,
953
+ [data-theme="dark"] .lesson-gotchas strong { color: #ffb300; }
954
+ [data-theme="dark"] .use-cases-list li,
955
+ [data-theme="dark"] .lesson-use-cases li { color: #b0bec5; }
956
+ [data-theme="dark"] .related-cmd { background: #1a237e; color: #90caf9; }
957
+ [data-theme="dark"] .man-link { background: #0d47a1; color: #90caf9; }
958
+ [data-theme="dark"] .subcmd-section { background: #0d253f; border-left-color: #4a9eff; }
862
959
 
863
960
  /* Tabs */
864
961
  .tabs {
@@ -1458,6 +1555,39 @@ def get_inline_css() -> str:
1458
1555
  .complexity-intermediate { background: #fff3e0; color: #e65100; }
1459
1556
  .complexity-advanced { background: #fce4ec; color: #c62828; }
1460
1557
 
1558
+ /* Enrichment: use cases */
1559
+ .use-cases-section, .lesson-use-cases { margin: 8px 0; }
1560
+ .use-cases-section h5, .lesson-use-cases strong { margin: 4px 0; color: #1a73e8; font-size: 0.85em; }
1561
+ .use-cases-list { padding-left: 18px; margin: 4px 0; }
1562
+ .use-cases-list li, .lesson-use-cases li { margin: 4px 0; line-height: 1.5; font-size: 0.9em; color: #444; }
1563
+ .lesson-use-cases ul { padding-left: 18px; margin: 4px 0; list-style: disc; }
1564
+ .lesson-use-cases li { font-size: 0.85em; color: #555; }
1565
+
1566
+ /* Enrichment: gotchas / pitfalls */
1567
+ .gotchas-section, .lesson-gotchas { margin: 8px 0; background: #fff8e1; padding: 8px 12px; border-radius: 6px; border-left: 3px solid #f9a825; }
1568
+ .gotchas-section h5, .lesson-gotchas strong { margin: 4px 0; color: #f57f17; font-size: 0.85em; }
1569
+ .gotchas-list { padding-left: 18px; margin: 4px 0; }
1570
+ .gotchas-list li, .lesson-gotchas li { margin: 4px 0; line-height: 1.5; font-size: 0.9em; color: #5d4037; }
1571
+ .lesson-gotchas ul { padding-left: 18px; margin: 4px 0; list-style: disc; }
1572
+
1573
+ /* Enrichment: related commands */
1574
+ .related-section { margin: 8px 0; }
1575
+ .related-section h5 { display: inline; margin-right: 6px; color: #666; font-size: 0.85em; }
1576
+ .related-cmd { background: #e8eaf6; color: #3949ab; padding: 2px 8px; border-radius: 10px; font-size: 0.8em; margin-right: 4px; cursor: default; }
1577
+
1578
+ /* Enrichment: man page link */
1579
+ .man-link { font-size: 0.75em; padding: 2px 8px; border-radius: 10px; background: #e3f2fd; color: #1565c0; text-decoration: none; margin-left: 8px; font-weight: 500; }
1580
+ .man-link:hover { background: #bbdefb; text-decoration: none; }
1581
+
1582
+ /* Quiz enrichment */
1583
+ .question-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px; }
1584
+ .quiz-meta { display: flex; gap: 6px; align-items: center; }
1585
+
1586
+ /* Lesson related commands */
1587
+ .lesson-related-section { margin: 16px 0 8px; padding: 12px; background: var(--bg-secondary); border-radius: var(--radius-md); border: 1px solid var(--border-color); }
1588
+ .lesson-related-section h4 { font-size: 0.9em; color: var(--text-secondary); margin-bottom: 8px; }
1589
+ .related-chips { display: flex; flex-wrap: wrap; gap: 6px; }
1590
+
1461
1591
  .syntax-highlighted .string {
1462
1592
  color: #ff6d01;
1463
1593
  }
@@ -2379,6 +2509,11 @@ def generate_html_files(
2379
2509
  'common_patterns': common_patterns[:6],
2380
2510
  'args': cmd.get('args', []),
2381
2511
  'is_new': False,
2512
+ 'man_url': cmd_info.get('man_url', ''),
2513
+ 'use_cases': cmd_info.get('use_cases', []),
2514
+ 'gotchas': cmd_info.get('gotchas', []),
2515
+ 'related': cmd_info.get('related', []),
2516
+ 'difficulty': cmd_info.get('difficulty', ''),
2382
2517
  })
2383
2518
 
2384
2519
  # Transform complexity distribution from numeric keys to string labels
@@ -2430,11 +2565,19 @@ def generate_html_files(
2430
2565
  else:
2431
2566
  option_texts.append(str(opt))
2432
2567
 
2568
+ # Extract base command from command_context for enrichment lookup
2569
+ cmd_ctx = quiz.get('command_context', '')
2570
+ base_cmd = cmd_ctx.split()[0] if cmd_ctx else ''
2571
+ q_cmd_info = COMMAND_DB.get(base_cmd, {})
2572
+
2433
2573
  formatted_quizzes.append({
2434
2574
  'question': quiz.get('question', ''),
2435
2575
  'options': option_texts,
2436
2576
  'correct_answer': correct_idx,
2437
2577
  'explanation': quiz.get('explanation', ''),
2578
+ 'difficulty': q_cmd_info.get('difficulty', ''),
2579
+ 'man_url': q_cmd_info.get('man_url', ''),
2580
+ 'base_command': base_cmd,
2438
2581
  })
2439
2582
 
2440
2583
  # Generate HTML