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.
- package/package.json +1 -1
- package/scripts/enrichment_builtins.py +1266 -0
- package/scripts/enrichment_coreutils.py +1499 -0
- package/scripts/enrichment_netproc.py +2270 -0
- package/scripts/enrichment_netsys.py +1601 -0
- package/scripts/enrichment_pkgcomp.py +2185 -0
- package/scripts/enrichment_textdev.py +2016 -0
- package/scripts/html_generator.py +144 -1
- package/scripts/knowledge_base.py +11521 -5648
- package/scripts/main.py +1 -1
- package/scripts/merge_enrichment.py +272 -0
|
@@ -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("&", "&"), {})
|
|
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("&", "&")
|
|
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-
|
|
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
|