sdtk-wiki-kit 0.2.1 → 0.3.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.
- package/README.md +8 -0
- package/assets/atlas/doc_atlas_viewer_template.html +519 -58
- package/bin/sdtk-wiki.js +0 -0
- package/package.json +1 -1
- package/src/commands/ask.js +2 -0
- package/src/commands/help.js +1 -0
- package/src/commands/init.js +1 -1
- package/src/commands/kaban.js +85 -0
- package/src/index.js +4 -0
- package/src/lib/wiki-ask.js +254 -19
- package/src/lib/wiki-config.js +3 -1
- package/src/lib/wiki-kaban-parse.js +529 -0
- package/src/lib/wiki-runner.js +46 -0
|
@@ -359,6 +359,7 @@ body.nav-open .page-nav-toggle{display:none}
|
|
|
359
359
|
#atlas-ask-model-select{flex:0 0 136px;width:136px}
|
|
360
360
|
#atlas-ask-mode-select{flex:1 1 140px;width:140px}
|
|
361
361
|
#atlas-ask-info-toggle{flex:0 0 36px}
|
|
362
|
+
#atlas-ask-path-filter{padding:0 12px;background-image:none;flex:1 1 120px}
|
|
362
363
|
.atlas-ask-send{display:inline-flex;align-items:center;justify-content:center;flex:0 0 42px;width:42px;height:42px;border-radius:999px;border:0;background:linear-gradient(135deg,#4f78ff 0%,#3156c9 100%);color:#ffffff;cursor:pointer;font-size:20px;font-weight:900;box-shadow:0 14px 24px rgba(49,86,201,0.26)}
|
|
363
364
|
.atlas-ask-send:hover{filter:brightness(1.03)}
|
|
364
365
|
.atlas-ask-send:disabled{opacity:.5;cursor:not-allowed}
|
|
@@ -407,6 +408,47 @@ body.nav-open .page-nav-toggle{display:none}
|
|
|
407
408
|
.atlas-ask-history-item strong{font-size:12px;color:#24344d}
|
|
408
409
|
.atlas-ask-history-meta{font-size:11px;color:#6d7d95;line-height:1.4}
|
|
409
410
|
.atlas-ask-history-preview{font-size:12px;color:#52606f;line-height:1.45}
|
|
411
|
+
.ask-scope-wrap{position:relative;flex:1 1 150px;min-width:0}
|
|
412
|
+
.ask-scope-btn{display:flex;align-items:center;gap:8px;width:100%;height:36px;padding:0 12px;border-radius:999px;border:1px solid #d9cfbf;background:#fff;color:#24344d;font-size:12px;font-weight:700;cursor:pointer;box-shadow:0 8px 18px rgba(15,23,42,0.04);text-align:left}
|
|
413
|
+
.ask-scope-btn:hover{border-color:#aebfe7;background:#f6f8ff}
|
|
414
|
+
.ask-scope-btn .scope-ico{flex:0 0 auto}
|
|
415
|
+
.ask-scope-btn .scope-label{flex:1 1 auto;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
416
|
+
.ask-scope-btn .scope-caret{flex:0 0 auto;color:#7d8fa8;font-size:9px}
|
|
417
|
+
.ask-scope-menu{display:none;position:absolute;left:0;bottom:calc(100% + 8px);z-index:5;flex-direction:column;gap:2px;padding:8px;min-width:248px;max-width:320px;background:rgba(255,255,255,0.99);border:1px solid #d9cfbf;border-radius:18px;box-shadow:0 18px 30px rgba(94,83,63,0.18);max-height:340px;overflow:auto}
|
|
418
|
+
.ask-scope-wrap.open .ask-scope-menu{display:flex}
|
|
419
|
+
.ask-scope-opt{display:flex;align-items:center;gap:10px;padding:9px 10px;border-radius:12px;cursor:pointer;color:#24344d}
|
|
420
|
+
.ask-scope-opt:hover{background:#f7f9ff}
|
|
421
|
+
.ask-scope-opt.active{background:#eef3ff;border:1px solid #cad7ff;padding:8px 9px}
|
|
422
|
+
.ask-scope-opt.disabled{opacity:.45;cursor:not-allowed;pointer-events:none}
|
|
423
|
+
.ask-scope-opt .opt-ico{flex:0 0 18px;text-align:center}
|
|
424
|
+
.ask-scope-opt .opt-copy{display:flex;align-items:center;min-width:0;flex:1}
|
|
425
|
+
.ask-scope-opt .opt-copy strong{font-size:12.5px;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
426
|
+
.ask-scope-opt .opt-check{flex:0 0 auto;color:#3156c9;font-weight:900;visibility:hidden}
|
|
427
|
+
.ask-scope-opt.active .opt-check{visibility:visible}
|
|
428
|
+
.ask-scope-sep{height:1px;background:#ece4d8;margin:4px 2px}
|
|
429
|
+
.ask-folder-block{display:none;flex-direction:column;gap:6px;padding:4px 4px 6px;margin:2px 0 0;border-top:1px dashed #e6ded1}
|
|
430
|
+
.ask-folder-block.open{display:flex}
|
|
431
|
+
.ask-folder-filter{height:32px;border-radius:999px;border:1px solid #d9cfbf;background:#fff;padding:0 12px;font:inherit;font-size:12px;color:#24344d}
|
|
432
|
+
.ask-folder-filter:focus{outline:none;border-color:#5f89ff;box-shadow:0 0 0 3px rgba(95,137,255,0.12)}
|
|
433
|
+
.ask-folder-list{display:flex;flex-direction:column;gap:1px;max-height:170px;overflow:auto}
|
|
434
|
+
.ask-folder-item{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:7px 10px;border-radius:10px;cursor:pointer;font-size:12px}
|
|
435
|
+
.ask-folder-item:hover{background:#f7f9ff}
|
|
436
|
+
.ask-folder-item.active{background:#eef3ff}
|
|
437
|
+
.ask-folder-item .f-path{font-family:'SF Mono',Consolas,monospace;color:#354153;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
438
|
+
.ask-folder-item .f-count{flex:0 0 auto;font-size:11px;font-weight:800;color:#6d7d95;background:#f3efe7;border:1px solid #e6ded1;border-radius:999px;padding:1px 8px}
|
|
439
|
+
.ask-sources{margin-top:2px;border:1px solid #e6ded1;border-radius:14px;background:rgba(255,255,255,0.9);overflow:hidden}
|
|
440
|
+
.ask-sources-head{display:flex;align-items:center;gap:8px;width:100%;padding:10px 12px;background:none;border:0;cursor:pointer;color:#52606f;font-size:12px;font-weight:700;text-align:left}
|
|
441
|
+
.ask-sources-head:hover{background:#f7f9ff}
|
|
442
|
+
.ask-sources-caret{transition:transform .15s ease;color:#7d8fa8;font-size:10px}
|
|
443
|
+
.ask-sources.open .ask-sources-caret{transform:rotate(90deg)}
|
|
444
|
+
.ask-sources-badge{display:inline-flex;align-items:center;justify-content:center;min-width:20px;height:18px;padding:0 6px;border-radius:999px;background:#3156c9;color:#fff;font-size:11px;font-weight:800}
|
|
445
|
+
.ask-sources-body{display:none;flex-direction:column;gap:6px;padding:4px 12px 12px}
|
|
446
|
+
.ask-sources.open .ask-sources-body{display:flex}
|
|
447
|
+
.ask-source-row{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:7px 10px;border:1px solid #ece4d8;border-radius:10px;background:#fff}
|
|
448
|
+
.ask-source-row .s-path{font-family:'SF Mono',Consolas,monospace;font-size:11.5px;color:#354153;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
449
|
+
.s-chip{flex:0 0 auto;font-size:10px;font-weight:800;letter-spacing:.04em;text-transform:uppercase;border-radius:999px;padding:2px 8px}
|
|
450
|
+
.s-chip.primary{color:#2f8f5b;background:#e7f6ee;border:1px solid #bfe6cf}
|
|
451
|
+
.s-chip.related{color:#3156c9;background:#eef3ff;border:1px solid #cad7ff}
|
|
410
452
|
@media (max-width: 1180px){
|
|
411
453
|
.atlas-ask-dock{position:relative;left:auto;top:auto;bottom:auto;width:100%;max-width:none;margin-top:14px}
|
|
412
454
|
.atlas-ask-dock:not(.open){width:100%}
|
|
@@ -482,6 +524,47 @@ body.nav-open .page-nav-toggle{display:none}
|
|
|
482
524
|
.graph-toolbar-overlay,.graph-toolbar-overlay.compact,.graph-toolbar-overlay.minimized{position:relative;top:auto;left:auto;width:100%;max-width:none;margin-bottom:14px}
|
|
483
525
|
.graph-focus-overlay,.graph-focus-overlay.minimized{position:relative;top:auto;right:auto;bottom:auto;width:100%;height:auto;max-height:none;pointer-events:auto}
|
|
484
526
|
}
|
|
527
|
+
/* BK-272 Agent Kaban board */
|
|
528
|
+
.kaban-header{display:flex;align-items:flex-start;flex-wrap:wrap;gap:8px;padding:8px 2px}
|
|
529
|
+
.kaban-feature-info{flex:1;min-width:0}
|
|
530
|
+
.kaban-feature-name{font-size:14px;font-weight:700;color:var(--graph-text)}
|
|
531
|
+
.kaban-meta{font-size:11px;color:var(--graph-muted);margin-top:2px}
|
|
532
|
+
.kaban-liveness{font-size:11px;color:#b84c00;font-weight:700;padding:2px 8px;border:1px solid rgba(184,76,0,.35);border-radius:4px;white-space:nowrap;background:rgba(240,136,62,.07)}
|
|
533
|
+
.kaban-freshness{font-size:10px;color:var(--graph-muted)}
|
|
534
|
+
.kaban-notice{margin:0 0 6px;padding:5px 10px;border-radius:5px;font-size:11px;background:rgba(184,76,0,.06);color:#b84c00;border:1px solid rgba(184,76,0,.18)}
|
|
535
|
+
.kaban-tabs{display:flex;border-bottom:1px solid var(--graph-border);margin-bottom:6px}
|
|
536
|
+
.kaban-tab{background:none;border:none;border-bottom:2px solid transparent;padding:5px 14px;font-size:11px;font-weight:600;color:var(--graph-muted);cursor:pointer;margin-bottom:-1px}
|
|
537
|
+
.kaban-tab:hover{color:var(--graph-text)}
|
|
538
|
+
.kaban-tab.active{color:var(--graph-text);border-bottom-color:#5f89ff}
|
|
539
|
+
.kaban-board-wrap{overflow-x:auto;padding-bottom:8px}
|
|
540
|
+
.kaban-board{display:grid;grid-template-columns:80px repeat(4,minmax(110px,1fr));min-width:540px;column-gap:5px;row-gap:0}
|
|
541
|
+
.kaban-col-header{font-size:9px;text-transform:uppercase;letter-spacing:.06em;font-weight:700;padding:3px 4px 6px;text-align:center;color:var(--graph-muted)}
|
|
542
|
+
.kaban-col-header.kaban-col-inprog{color:#3156c9}
|
|
543
|
+
.kaban-col-header.kaban-col-pending{color:#b84c00}
|
|
544
|
+
.kaban-col-header.kaban-col-done{color:#1a7f37}
|
|
545
|
+
.kaban-swimlane-header{font-size:8px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--graph-muted);padding:7px 4px 3px;text-align:right;border-top:1px solid var(--graph-border)}
|
|
546
|
+
.kaban-cell{min-height:28px;padding:3px 2px;border-top:1px solid var(--graph-border);display:flex;flex-direction:column;gap:3px}
|
|
547
|
+
.kaban-cell.kaban-cell-inprog .kaban-card{border-left:3px solid #3156c9}
|
|
548
|
+
.kaban-cell.kaban-cell-pending .kaban-card{border-left:3px solid #b84c00}
|
|
549
|
+
.kaban-cell.kaban-cell-done .kaban-card{border-left:3px solid #1a7f37}
|
|
550
|
+
.kaban-cell.kaban-cell-todo .kaban-card{border-left:3px solid var(--border)}
|
|
551
|
+
.kaban-card{background:var(--surface);border:1px solid var(--border);border-radius:4px;padding:5px 7px;font-size:11px;color:var(--text);cursor:pointer;line-height:1.4;transition:background .12s}
|
|
552
|
+
.kaban-card:hover{background:var(--surface2)}
|
|
553
|
+
.kaban-card-title{font-weight:600}
|
|
554
|
+
.kaban-card-badges{display:flex;gap:3px;flex-wrap:wrap;margin-top:2px}
|
|
555
|
+
.kaban-badge{font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:.04em;padding:1px 4px;border-radius:3px;display:inline-block}
|
|
556
|
+
.kaban-badge-attention{background:rgba(184,76,0,.14);color:#b84c00;border:1px solid rgba(184,76,0,.28)}
|
|
557
|
+
.kaban-badge-gate{background:rgba(100,60,200,.08);color:#6438c8;border:1px solid rgba(100,60,200,.2)}
|
|
558
|
+
.kaban-card-detail{position:fixed;top:10%;left:10%;right:10%;max-height:76vh;z-index:200;background:var(--surface);border:1px solid var(--border);border-radius:10px;display:flex;flex-direction:column;box-shadow:0 16px 48px rgba(0,0,0,.7)}
|
|
559
|
+
.kaban-detail-header{display:flex;align-items:flex-start;gap:10px;padding:12px 14px 8px;border-bottom:1px solid var(--border)}
|
|
560
|
+
.kaban-detail-phase{font-size:9px;text-transform:uppercase;letter-spacing:.07em;color:var(--text2);font-weight:700}
|
|
561
|
+
.kaban-detail-title{font-size:14px;font-weight:700;color:var(--text);margin-top:3px}
|
|
562
|
+
.kaban-detail-close{background:none;border:none;color:var(--text2);font-size:18px;cursor:pointer;padding:0 4px;line-height:1;border-radius:3px;flex-shrink:0}
|
|
563
|
+
.kaban-detail-close:hover{color:var(--text);background:var(--surface2)}
|
|
564
|
+
.kaban-detail-body{padding:12px 14px;overflow-y:auto;flex:1;font-size:12px;line-height:1.6}
|
|
565
|
+
.kaban-detail-row{display:flex;gap:8px;margin-bottom:5px}
|
|
566
|
+
.kaban-detail-label{font-size:10px;text-transform:uppercase;letter-spacing:.05em;color:var(--text2);font-weight:600;min-width:68px;flex-shrink:0}
|
|
567
|
+
.kaban-detail-value{color:var(--text);flex:1;word-break:break-word}
|
|
485
568
|
|
|
486
569
|
</style>
|
|
487
570
|
</head>
|
|
@@ -503,25 +586,33 @@ body.nav-open .page-nav-toggle{display:none}
|
|
|
503
586
|
<p>Project-local wiki and knowledge graph - generated __ATLAS_GENERATED__</p>
|
|
504
587
|
</div>
|
|
505
588
|
<div class="screen-scroll">
|
|
506
|
-
<div class="
|
|
507
|
-
<div class="
|
|
508
|
-
<
|
|
509
|
-
<
|
|
589
|
+
<div class="kaban-header" id="kaban-header">
|
|
590
|
+
<div class="kaban-feature-info">
|
|
591
|
+
<div class="kaban-feature-name" id="kaban-feature-name">Agent Kaban Board</div>
|
|
592
|
+
<div class="kaban-meta" id="kaban-meta">Loading pipeline data...</div>
|
|
510
593
|
</div>
|
|
511
|
-
<div class="
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
594
|
+
<div class="kaban-liveness" id="kaban-liveness" style="display:none">⚠ <span id="kaban-liveness-text"></span></div>
|
|
595
|
+
<div class="kaban-freshness" id="kaban-freshness"></div>
|
|
596
|
+
</div>
|
|
597
|
+
<div class="kaban-notice" id="kaban-notice" style="display:none"></div>
|
|
598
|
+
<div class="kaban-tabs">
|
|
599
|
+
<button class="kaban-tab active" id="kaban-tab-pipeline" onclick="switchKabanTab('pipeline')">Pipeline</button>
|
|
600
|
+
<button class="kaban-tab" id="kaban-tab-quality" onclick="switchKabanTab('quality')">Quality Gates</button>
|
|
601
|
+
</div>
|
|
602
|
+
<div class="kaban-board-wrap">
|
|
603
|
+
<div id="kaban-board-pipeline"></div>
|
|
604
|
+
<div id="kaban-board-quality" style="display:none"></div>
|
|
605
|
+
</div>
|
|
606
|
+
</div>
|
|
607
|
+
<div class="kaban-card-detail" id="kaban-card-detail" style="display:none">
|
|
608
|
+
<div class="kaban-detail-header">
|
|
609
|
+
<div style="flex:1;min-width:0">
|
|
610
|
+
<div class="kaban-detail-phase" id="kd-phase"></div>
|
|
611
|
+
<div class="kaban-detail-title" id="kd-title"></div>
|
|
522
612
|
</div>
|
|
613
|
+
<button class="kaban-detail-close" onclick="closeKabanDetail()" aria-label="Close card detail" title="Close card detail">×</button>
|
|
523
614
|
</div>
|
|
524
|
-
<div
|
|
615
|
+
<div class="kaban-detail-body" id="kd-body"></div>
|
|
525
616
|
</div>
|
|
526
617
|
</div>
|
|
527
618
|
</div>
|
|
@@ -614,7 +705,7 @@ body.nav-open .page-nav-toggle{display:none}
|
|
|
614
705
|
<button class="graph-focus-toggle atlas-ask-collapse" id="atlas-ask-toggle" title="Hide Ask SDTK-WIKI" onclick="toggleWikiAsk(false)">▾</button>
|
|
615
706
|
<div class="atlas-ask-attachments" id="atlas-ask-attachments"></div>
|
|
616
707
|
<div class="atlas-ask-input-wrap">
|
|
617
|
-
<textarea class="atlas-ask-input" id="atlas-ask-input" placeholder="Ask about
|
|
708
|
+
<textarea class="atlas-ask-input" id="atlas-ask-input" placeholder="Ask something about your docs..."></textarea>
|
|
618
709
|
<div class="atlas-ask-mention-results" id="atlas-ask-mention-results"></div>
|
|
619
710
|
</div>
|
|
620
711
|
<div class="atlas-ask-source-summary" id="atlas-ask-source-summary"></div>
|
|
@@ -622,11 +713,40 @@ body.nav-open .page-nav-toggle{display:none}
|
|
|
622
713
|
<div class="atlas-ask-controls">
|
|
623
714
|
<select class="atlas-ask-mode-select" id="atlas-ask-runtime-select" onchange="setWikiAskRuntimeAgent(this.value)" aria-label="Select runtime agent"></select>
|
|
624
715
|
<select class="atlas-ask-mode-select" id="atlas-ask-model-select" onchange="setWikiAskModel(this.value)" aria-label="Select model"></select>
|
|
625
|
-
<
|
|
626
|
-
<
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
716
|
+
<div class="ask-scope-wrap" id="ask-scope-wrap">
|
|
717
|
+
<button class="ask-scope-btn" id="ask-scope-btn" onclick="toggleWikiAskScopeMenu(event)" aria-haspopup="listbox" aria-expanded="false" title="Select Ask scope">
|
|
718
|
+
<span class="scope-ico" id="ask-scope-ico">📚</span>
|
|
719
|
+
<span class="scope-label" id="ask-scope-label">All Docs</span>
|
|
720
|
+
<span class="scope-caret">▲</span>
|
|
721
|
+
</button>
|
|
722
|
+
<div class="ask-scope-menu" id="ask-scope-menu" role="listbox">
|
|
723
|
+
<div class="ask-scope-opt active" data-scope="all" role="option" tabindex="0" onclick="pickWikiAskScope('all')" title="Hỏi trên toàn bộ tài liệu đã index (mặc định).">
|
|
724
|
+
<span class="opt-ico">📚</span>
|
|
725
|
+
<span class="opt-copy"><strong>All Docs</strong></span>
|
|
726
|
+
<span class="opt-check">✓</span>
|
|
727
|
+
</div>
|
|
728
|
+
<div class="ask-scope-opt" id="ask-scope-opt-folder" data-scope="folder" role="option" tabindex="0" onclick="toggleWikiAskFolderBlock(event)" title="Chọn một thư mục có thật để giới hạn phạm vi hỏi.">
|
|
729
|
+
<span class="opt-ico">📁</span>
|
|
730
|
+
<span class="opt-copy"><strong>By folder</strong></span>
|
|
731
|
+
<span class="opt-check">✓</span>
|
|
732
|
+
</div>
|
|
733
|
+
<div class="ask-folder-block" id="ask-folder-block">
|
|
734
|
+
<input class="ask-folder-filter" id="ask-folder-filter" type="text" placeholder="Filter folders…" oninput="filterWikiAskFolders(this.value)" aria-label="Filter folders by name">
|
|
735
|
+
<div class="ask-folder-list" id="ask-folder-list"></div>
|
|
736
|
+
</div>
|
|
737
|
+
<div class="ask-scope-sep"></div>
|
|
738
|
+
<div class="ask-scope-opt" id="ask-scope-opt-focus" data-scope="focus" role="option" tabindex="0" onclick="pickWikiAskScope('focus')" title="Tài liệu đang focus + các tài liệu liên quan cùng BK / knowledge / skill.">
|
|
739
|
+
<span class="opt-ico">🎯</span>
|
|
740
|
+
<span class="opt-copy"><strong>This doc + related</strong></span>
|
|
741
|
+
<span class="opt-check">✓</span>
|
|
742
|
+
</div>
|
|
743
|
+
<div class="ask-scope-opt" id="ask-scope-opt-selected" data-scope="selected" role="option" tabindex="0" onclick="pickWikiAskScope('selected')" title="Chỉ hỏi trên các tài liệu bạn đã đính kèm.">
|
|
744
|
+
<span class="opt-ico">✓</span>
|
|
745
|
+
<span class="opt-copy"><strong id="ask-scope-selected-label">Selected docs</strong></span>
|
|
746
|
+
<span class="opt-check">✓</span>
|
|
747
|
+
</div>
|
|
748
|
+
</div>
|
|
749
|
+
</div>
|
|
630
750
|
<button class="atlas-ask-icon-btn" id="atlas-ask-info-toggle" title="Show grounding info" onclick="toggleWikiAskAdvanced()">i</button>
|
|
631
751
|
</div>
|
|
632
752
|
<button class="atlas-ask-send" id="atlas-ask-submit" onclick="submitWikiAsk()" aria-label="Submit SDTK-WIKI Ask" title="Submit SDTK-WIKI Ask">↑</button>
|
|
@@ -740,26 +860,179 @@ const FAMILY_GLYPHS = {
|
|
|
740
860
|
};
|
|
741
861
|
const GRAPH_EDGE_COLORS = { references_path: 'rgba(95,137,255,0.38)', references_wiki_link: 'rgba(46,181,125,0.44)' };
|
|
742
862
|
const GRAPH_FRAME_MS = 40;
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
}
|
|
863
|
+
// BK-272: Agent Kaban board — state, render, and poll
|
|
864
|
+
var kabanState = { data: null, activeTab: 'pipeline', pollTimer: null, lastFetch: null };
|
|
865
|
+
const KABAN_POLL_MS = 3000;
|
|
866
|
+
const KABAN_LIVENESS_MIN_JS = 15;
|
|
867
|
+
const KABAN_COLS = ['todo', 'in_progress', 'pending', 'done'];
|
|
868
|
+
const KABAN_COL_LABELS = { todo: 'Todo', in_progress: 'In Progress', pending: 'Pending', done: 'Done' };
|
|
869
|
+
const KABAN_COL_CSS = { todo: '', in_progress: 'kaban-col-inprog', pending: 'kaban-col-pending', done: 'kaban-col-done' };
|
|
870
|
+
const KABAN_CELL_CSS = { todo: 'kaban-cell-todo', in_progress: 'kaban-cell-inprog', pending: 'kaban-cell-pending', done: 'kaban-cell-done' };
|
|
871
|
+
|
|
872
|
+
function safeKabanHtml(s) {
|
|
873
|
+
return String(s || '').replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
|
874
|
+
}
|
|
875
|
+
function formatKabanFreshness(dt) {
|
|
876
|
+
if (!dt) return '';
|
|
877
|
+
const d = Math.floor((new Date() - dt) / 1000);
|
|
878
|
+
if (d < 5) return 'just now';
|
|
879
|
+
if (d < 60) return d + 's ago';
|
|
880
|
+
if (d < 3600) return Math.floor(d / 60) + 'm ago';
|
|
881
|
+
return Math.floor(d / 3600) + 'h ago';
|
|
882
|
+
}
|
|
883
|
+
function renderKabanCard(card) {
|
|
884
|
+
const badges = [];
|
|
885
|
+
if (card.attention) badges.push('<span class="kaban-badge kaban-badge-attention">⚠ Pending</span>');
|
|
886
|
+
if (card.isGate) badges.push('<span class="kaban-badge kaban-badge-gate">GATE</span>');
|
|
887
|
+
const id = safeKabanHtml(card.id);
|
|
888
|
+
const tab = safeKabanHtml(kabanState.activeTab);
|
|
889
|
+
return '<div class="kaban-card" onclick="openKabanDetail(\'' + id + '\',\'' + tab + '\')" role="button" tabindex="0">' +
|
|
890
|
+
'<div class="kaban-card-title">' + safeKabanHtml(card.title || card.id) + '</div>' +
|
|
891
|
+
(badges.length ? '<div class="kaban-card-badges">' + badges.join('') + '</div>' : '') +
|
|
892
|
+
'</div>';
|
|
893
|
+
}
|
|
894
|
+
function renderKabanBoard(containerId, cards, agents) {
|
|
895
|
+
const container = document.getElementById(containerId);
|
|
896
|
+
if (!container) return;
|
|
897
|
+
if (!cards || cards.length === 0) {
|
|
898
|
+
container.innerHTML = '<div style="padding:16px;text-align:center;font-size:11px;color:var(--text2)">No data — SHARED_PLANNING.md or QUALITY_CHECKLIST.md not found in project root.</div>';
|
|
899
|
+
return;
|
|
900
|
+
}
|
|
901
|
+
let html = '<div class="kaban-board">';
|
|
902
|
+
html += '<div class="kaban-col-header"></div>';
|
|
903
|
+
for (const col of KABAN_COLS) {
|
|
904
|
+
html += '<div class="kaban-col-header ' + (KABAN_COL_CSS[col] || '') + '">' + KABAN_COL_LABELS[col] + '</div>';
|
|
905
|
+
}
|
|
906
|
+
for (const agent of agents) {
|
|
907
|
+
html += '<div class="kaban-swimlane-header">' + safeKabanHtml(agent) + '</div>';
|
|
908
|
+
for (const col of KABAN_COLS) {
|
|
909
|
+
const cellCards = cards.filter(function(c){ return c.agent === agent && c.column === col; });
|
|
910
|
+
html += '<div class="kaban-cell ' + KABAN_CELL_CSS[col] + '">';
|
|
911
|
+
for (const c of cellCards) html += renderKabanCard(c);
|
|
912
|
+
html += '</div>';
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
const otherCards = cards.filter(function(c){ return !agents.includes(c.agent); });
|
|
916
|
+
if (otherCards.length > 0) {
|
|
917
|
+
html += '<div class="kaban-swimlane-header">OTHER</div>';
|
|
918
|
+
for (const col of KABAN_COLS) {
|
|
919
|
+
const cellCards = otherCards.filter(function(c){ return c.column === col; });
|
|
920
|
+
html += '<div class="kaban-cell ' + KABAN_CELL_CSS[col] + '">';
|
|
921
|
+
for (const c of cellCards) html += renderKabanCard(c);
|
|
922
|
+
html += '</div>';
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
html += '</div>';
|
|
926
|
+
container.innerHTML = html;
|
|
927
|
+
}
|
|
928
|
+
function renderKaban(data) {
|
|
929
|
+
if (!data) return;
|
|
930
|
+
const meta = data.meta || {};
|
|
931
|
+
const agents = data.agents || ['PM','BA','ARCH','DEV','QA'];
|
|
932
|
+
const nameEl = document.getElementById('kaban-feature-name');
|
|
933
|
+
if (nameEl) nameEl.textContent = meta.featureName || meta.featureKey || 'Agent Kaban Board';
|
|
934
|
+
const metaEl = document.getElementById('kaban-meta');
|
|
935
|
+
if (metaEl) {
|
|
936
|
+
const parts = [];
|
|
937
|
+
if (meta.featureKey) parts.push(meta.featureKey);
|
|
938
|
+
if (meta.lastUpdated) parts.push('Updated: ' + meta.lastUpdated);
|
|
939
|
+
metaEl.textContent = parts.join(' · ') || 'No pipeline data';
|
|
940
|
+
}
|
|
941
|
+
const freshEl = document.getElementById('kaban-freshness');
|
|
942
|
+
if (freshEl && kabanState.lastFetch) freshEl.textContent = 'Fetched ' + formatKabanFreshness(kabanState.lastFetch);
|
|
943
|
+
const livenessEl = document.getElementById('kaban-liveness');
|
|
944
|
+
const livenessTextEl = document.getElementById('kaban-liveness-text');
|
|
945
|
+
if (livenessEl && meta.lastUpdated) {
|
|
946
|
+
try {
|
|
947
|
+
const lu = new Date(meta.lastUpdated.replace(' ','T'));
|
|
948
|
+
const diffMin = Math.floor((new Date() - lu) / 60000);
|
|
949
|
+
if (diffMin > KABAN_LIVENESS_MIN_JS && !isNaN(diffMin)) {
|
|
950
|
+
if (livenessTextEl) livenessTextEl.textContent = 'No movement for ' + diffMin + ' min';
|
|
951
|
+
livenessEl.style.display = '';
|
|
952
|
+
} else { livenessEl.style.display = 'none'; }
|
|
953
|
+
} catch(_) { livenessEl.style.display = 'none'; }
|
|
954
|
+
} else if (livenessEl) { livenessEl.style.display = 'none'; }
|
|
955
|
+
const noticeEl = document.getElementById('kaban-notice');
|
|
956
|
+
if (noticeEl) {
|
|
957
|
+
const notices = [];
|
|
958
|
+
if (!meta.pipelinePresent) notices.push('SHARED_PLANNING.md not found');
|
|
959
|
+
if (!meta.qualityPresent) notices.push('QUALITY_CHECKLIST.md not found');
|
|
960
|
+
(meta.errors || []).forEach(function(e){ notices.push(e); });
|
|
961
|
+
if (notices.length > 0) { noticeEl.textContent = notices.join(' · '); noticeEl.style.display = ''; }
|
|
962
|
+
else { noticeEl.style.display = 'none'; }
|
|
963
|
+
}
|
|
964
|
+
renderKabanBoard('kaban-board-pipeline', (data.pipeline || {}).cards || [], agents);
|
|
965
|
+
renderKabanBoard('kaban-board-quality', (data.quality || {}).cards || [], agents);
|
|
966
|
+
}
|
|
967
|
+
function openKabanDetail(cardId, tab) {
|
|
968
|
+
if (!kabanState.data) return;
|
|
969
|
+
const src = tab === 'quality' ? (kabanState.data.quality || {}) : (kabanState.data.pipeline || {});
|
|
970
|
+
const card = (src.cards || []).find(function(c){ return c.id === cardId; });
|
|
971
|
+
if (!card) return;
|
|
972
|
+
const phaseEl = document.getElementById('kd-phase');
|
|
973
|
+
const titleEl = document.getElementById('kd-title');
|
|
974
|
+
const bodyEl = document.getElementById('kd-body');
|
|
975
|
+
const detailEl = document.getElementById('kaban-card-detail');
|
|
976
|
+
if (!detailEl) return;
|
|
977
|
+
if (phaseEl) phaseEl.textContent = (card.agent || '') + (card.phase ? ' · ' + card.phase : '');
|
|
978
|
+
if (titleEl) titleEl.textContent = card.title || card.id;
|
|
979
|
+
if (bodyEl) {
|
|
980
|
+
const rows = [];
|
|
981
|
+
function addRow(label, value) {
|
|
982
|
+
if (!value) return;
|
|
983
|
+
rows.push('<div class="kaban-detail-row"><span class="kaban-detail-label">' + safeKabanHtml(label) + '</span><span class="kaban-detail-value">' + safeKabanHtml(value) + '</span></div>');
|
|
984
|
+
}
|
|
985
|
+
addRow('Column', KABAN_COL_LABELS[card.column] || card.column);
|
|
986
|
+
addRow('Status', card.rawStatus);
|
|
987
|
+
addRow('Owner', card.owner);
|
|
988
|
+
addRow('Artifact', card.artifact);
|
|
989
|
+
addRow('Notes', card.notes);
|
|
990
|
+
addRow('Issue', card.issue);
|
|
991
|
+
addRow('Last update', card.lastUpdate);
|
|
992
|
+
addRow('Handoff →', card.handoffNext);
|
|
993
|
+
if (card.isGate) rows.push('<div style="margin-top:8px"><span class="kaban-badge kaban-badge-gate">GATE CHECKPOINT</span></div>');
|
|
994
|
+
if (card.attention) rows.push('<div style="margin-top:4px"><span class="kaban-badge kaban-badge-attention">⚠ Needs attention</span></div>');
|
|
995
|
+
bodyEl.innerHTML = rows.join('') || '<span style="color:var(--text2)">No additional detail.</span>';
|
|
996
|
+
}
|
|
997
|
+
detailEl.style.display = 'flex';
|
|
998
|
+
}
|
|
999
|
+
function closeKabanDetail() {
|
|
1000
|
+
const el = document.getElementById('kaban-card-detail');
|
|
1001
|
+
if (el) el.style.display = 'none';
|
|
1002
|
+
}
|
|
1003
|
+
function switchKabanTab(tab) {
|
|
1004
|
+
kabanState.activeTab = tab;
|
|
1005
|
+
const ptab = document.getElementById('kaban-tab-pipeline');
|
|
1006
|
+
const qtab = document.getElementById('kaban-tab-quality');
|
|
1007
|
+
const pboard = document.getElementById('kaban-board-pipeline');
|
|
1008
|
+
const qboard = document.getElementById('kaban-board-quality');
|
|
1009
|
+
if (ptab) ptab.classList.toggle('active', tab === 'pipeline');
|
|
1010
|
+
if (qtab) qtab.classList.toggle('active', tab === 'quality');
|
|
1011
|
+
if (pboard) pboard.style.display = tab === 'pipeline' ? '' : 'none';
|
|
1012
|
+
if (qboard) qboard.style.display = tab === 'quality' ? '' : 'none';
|
|
1013
|
+
closeKabanDetail();
|
|
1014
|
+
}
|
|
1015
|
+
async function fetchKabanData() {
|
|
1016
|
+
try {
|
|
1017
|
+
const resp = await fetch('/api/kaban');
|
|
1018
|
+
if (!resp.ok) throw new Error('HTTP ' + resp.status);
|
|
1019
|
+
const data = await resp.json();
|
|
1020
|
+
kabanState.data = data;
|
|
1021
|
+
kabanState.lastFetch = new Date();
|
|
1022
|
+
renderKaban(data);
|
|
1023
|
+
} catch(e) {
|
|
1024
|
+
const noticeEl = document.getElementById('kaban-notice');
|
|
1025
|
+
if (noticeEl) { noticeEl.textContent = 'Could not load kaban data: ' + e.message; noticeEl.style.display = ''; }
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
function startKabanPoll() {
|
|
1029
|
+
stopKabanPoll();
|
|
1030
|
+
fetchKabanData();
|
|
1031
|
+
kabanState.pollTimer = setInterval(fetchKabanData, KABAN_POLL_MS);
|
|
1032
|
+
}
|
|
1033
|
+
function stopKabanPoll() {
|
|
1034
|
+
if (kabanState.pollTimer) { clearInterval(kabanState.pollTimer); kabanState.pollTimer = null; }
|
|
1035
|
+
}
|
|
763
1036
|
|
|
764
1037
|
|
|
765
1038
|
function applySidebarState(collapsed) {
|
|
@@ -805,6 +1078,7 @@ function showPanel(name, btn) {
|
|
|
805
1078
|
} else {
|
|
806
1079
|
stopGraphAnimation();
|
|
807
1080
|
}
|
|
1081
|
+
if (name === 'dash') { startKabanPoll(); } else { stopKabanPoll(); }
|
|
808
1082
|
}
|
|
809
1083
|
|
|
810
1084
|
let activeFamily = null;
|
|
@@ -879,7 +1153,8 @@ const graphState = {
|
|
|
879
1153
|
};
|
|
880
1154
|
const wikiAskState = {
|
|
881
1155
|
open: false,
|
|
882
|
-
mode: '
|
|
1156
|
+
mode: 'all-docs',
|
|
1157
|
+
docPathFilter: '',
|
|
883
1158
|
selectedDocIds: [],
|
|
884
1159
|
status: 'idle',
|
|
885
1160
|
answer: null,
|
|
@@ -1433,8 +1708,165 @@ function openGraphToolbarPeek(event) {
|
|
|
1433
1708
|
toggleGraphToolbarMinimized(false);
|
|
1434
1709
|
}
|
|
1435
1710
|
function getWikiAskModeLabel(mode) {
|
|
1436
|
-
return ({ 'current-focus': '
|
|
1711
|
+
return ({ 'all-docs': 'All Docs', 'current-focus': 'This doc + related', 'visible-group': 'All Docs', 'selected-docs': 'Selected docs' }[mode]) || 'Ask SDTK-WIKI';
|
|
1712
|
+
}
|
|
1713
|
+
function getWikiAskAllDocIds(pathFilter) {
|
|
1714
|
+
const filter = (pathFilter || '').trim().toLowerCase();
|
|
1715
|
+
return docs.filter(d => {
|
|
1716
|
+
if (!filter) return true;
|
|
1717
|
+
const docPath = (d.sourcePath || d.path || d.id || '').toLowerCase();
|
|
1718
|
+
return docPath.startsWith(filter);
|
|
1719
|
+
}).map(d => d.id);
|
|
1720
|
+
}
|
|
1721
|
+
function setWikiAskDocPathFilter(value) {
|
|
1722
|
+
wikiAskState.docPathFilter = value || '';
|
|
1723
|
+
renderWikiAsk();
|
|
1724
|
+
}
|
|
1725
|
+
function getWikiAskFolderList() {
|
|
1726
|
+
var counts = {};
|
|
1727
|
+
for (var i = 0; i < docs.length; i++) {
|
|
1728
|
+
var d = docs[i];
|
|
1729
|
+
var sp = (d.sourcePath || d.path || d.id || '').replace(/\\/g, '/');
|
|
1730
|
+
if (!sp) continue;
|
|
1731
|
+
var parts = sp.split('/');
|
|
1732
|
+
if (parts.length >= 2) {
|
|
1733
|
+
var prefix = parts.slice(0, 2).join('/') + '/';
|
|
1734
|
+
counts[prefix] = (counts[prefix] || 0) + 1;
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
return Object.entries(counts)
|
|
1738
|
+
.sort(function(a, b) { return b[1] - a[1] || a[0].localeCompare(b[0]); })
|
|
1739
|
+
.slice(0, 8)
|
|
1740
|
+
.map(function(e) { return { path: e[0], count: e[1] }; });
|
|
1741
|
+
}
|
|
1742
|
+
function renderWikiAskFolderList() {
|
|
1743
|
+
var list = document.getElementById('ask-folder-list');
|
|
1744
|
+
if (!list) return;
|
|
1745
|
+
var folders = getWikiAskFolderList();
|
|
1746
|
+
if (!folders.length) {
|
|
1747
|
+
list.innerHTML = '<div style="padding:8px 10px;font-size:12px;color:#6d7d95">No folders found.</div>';
|
|
1748
|
+
return;
|
|
1749
|
+
}
|
|
1750
|
+
list.innerHTML = folders.map(function(f) {
|
|
1751
|
+
var active = wikiAskState.docPathFilter === f.path ? ' active' : '';
|
|
1752
|
+
return '<div class="ask-folder-item' + active + '" data-path="' + escapeHtml(f.path) + '" onclick="pickWikiAskFolder(' + JSON.stringify(f.path) + ')"><span class="f-path">' + escapeHtml(f.path) + '</span><span class="f-count">' + f.count + '</span></div>';
|
|
1753
|
+
}).join('');
|
|
1437
1754
|
}
|
|
1755
|
+
function toggleWikiAskScopeMenu(event) {
|
|
1756
|
+
if (event) event.stopPropagation();
|
|
1757
|
+
var wrap = document.getElementById('ask-scope-wrap');
|
|
1758
|
+
if (!wrap) return;
|
|
1759
|
+
var isOpen = wrap.classList.contains('open');
|
|
1760
|
+
if (!isOpen) {
|
|
1761
|
+
renderWikiAskFolderList();
|
|
1762
|
+
syncWikiAskScopeMenu();
|
|
1763
|
+
}
|
|
1764
|
+
wrap.classList.toggle('open', !isOpen);
|
|
1765
|
+
var btn = document.getElementById('ask-scope-btn');
|
|
1766
|
+
if (btn) btn.setAttribute('aria-expanded', String(!isOpen));
|
|
1767
|
+
}
|
|
1768
|
+
function closeWikiAskScopeMenu() {
|
|
1769
|
+
var wrap = document.getElementById('ask-scope-wrap');
|
|
1770
|
+
if (wrap) {
|
|
1771
|
+
wrap.classList.remove('open');
|
|
1772
|
+
var btn = document.getElementById('ask-scope-btn');
|
|
1773
|
+
if (btn) btn.setAttribute('aria-expanded', 'false');
|
|
1774
|
+
}
|
|
1775
|
+
}
|
|
1776
|
+
function syncWikiAskScopeMenu() {
|
|
1777
|
+
var menu = document.getElementById('ask-scope-menu');
|
|
1778
|
+
if (!menu) return;
|
|
1779
|
+
menu.querySelectorAll('.ask-scope-opt').forEach(function(opt) { opt.classList.remove('active'); });
|
|
1780
|
+
var scope = wikiAskState.mode === 'current-focus' ? 'focus'
|
|
1781
|
+
: wikiAskState.mode === 'selected-docs' ? 'selected'
|
|
1782
|
+
: wikiAskState.docPathFilter ? 'folder'
|
|
1783
|
+
: 'all';
|
|
1784
|
+
var target = menu.querySelector('[data-scope="' + scope + '"]');
|
|
1785
|
+
if (target) target.classList.add('active');
|
|
1786
|
+
var focusOpt = document.getElementById('ask-scope-opt-focus');
|
|
1787
|
+
var focusId = typeof getGraphFocusId !== 'undefined' ? getGraphFocusId() : null;
|
|
1788
|
+
if (focusOpt) {
|
|
1789
|
+
if (focusId) { focusOpt.classList.remove('disabled'); focusOpt.removeAttribute('aria-disabled'); }
|
|
1790
|
+
else { focusOpt.classList.add('disabled'); focusOpt.setAttribute('aria-disabled', 'true'); }
|
|
1791
|
+
}
|
|
1792
|
+
var selectedOpt = document.getElementById('ask-scope-opt-selected');
|
|
1793
|
+
if (selectedOpt) {
|
|
1794
|
+
var selLabel = document.getElementById('ask-scope-selected-label');
|
|
1795
|
+
if (wikiAskState.selectedDocIds.length > 0) {
|
|
1796
|
+
selectedOpt.style.display = '';
|
|
1797
|
+
if (selLabel) selLabel.textContent = 'Selected docs (' + wikiAskState.selectedDocIds.length + ')';
|
|
1798
|
+
} else { selectedOpt.style.display = 'none'; }
|
|
1799
|
+
}
|
|
1800
|
+
if (scope === 'folder') {
|
|
1801
|
+
var folderBlock = document.getElementById('ask-folder-block');
|
|
1802
|
+
if (folderBlock) folderBlock.classList.add('open');
|
|
1803
|
+
document.querySelectorAll('#ask-folder-list .ask-folder-item').forEach(function(item) {
|
|
1804
|
+
item.classList.toggle('active', item.dataset.path === wikiAskState.docPathFilter);
|
|
1805
|
+
});
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
function pickWikiAskScope(scope) {
|
|
1809
|
+
if (scope === 'focus') {
|
|
1810
|
+
var focusId = typeof getGraphFocusId !== 'undefined' ? getGraphFocusId() : null;
|
|
1811
|
+
if (!focusId) return;
|
|
1812
|
+
wikiAskState.mode = 'current-focus';
|
|
1813
|
+
wikiAskState.docPathFilter = '';
|
|
1814
|
+
} else if (scope === 'selected') {
|
|
1815
|
+
wikiAskState.mode = 'selected-docs';
|
|
1816
|
+
wikiAskState.docPathFilter = '';
|
|
1817
|
+
} else {
|
|
1818
|
+
wikiAskState.mode = 'all-docs';
|
|
1819
|
+
wikiAskState.docPathFilter = '';
|
|
1820
|
+
}
|
|
1821
|
+
closeWikiAskScopeMenu();
|
|
1822
|
+
renderWikiAsk();
|
|
1823
|
+
}
|
|
1824
|
+
function toggleWikiAskFolderBlock(event) {
|
|
1825
|
+
if (event) event.stopPropagation();
|
|
1826
|
+
var block = document.getElementById('ask-folder-block');
|
|
1827
|
+
if (!block) return;
|
|
1828
|
+
var isOpen = block.classList.contains('open');
|
|
1829
|
+
block.classList.toggle('open', !isOpen);
|
|
1830
|
+
if (!isOpen) { var filter = document.getElementById('ask-folder-filter'); if (filter) filter.focus(); }
|
|
1831
|
+
}
|
|
1832
|
+
function pickWikiAskFolder(path) {
|
|
1833
|
+
wikiAskState.mode = 'all-docs';
|
|
1834
|
+
wikiAskState.docPathFilter = path;
|
|
1835
|
+
document.querySelectorAll('#ask-folder-list .ask-folder-item').forEach(function(item) {
|
|
1836
|
+
item.classList.toggle('active', item.dataset.path === path);
|
|
1837
|
+
});
|
|
1838
|
+
closeWikiAskScopeMenu();
|
|
1839
|
+
renderWikiAsk();
|
|
1840
|
+
}
|
|
1841
|
+
function filterWikiAskFolders(q) {
|
|
1842
|
+
var query = (q || '').trim().toLowerCase();
|
|
1843
|
+
document.querySelectorAll('#ask-folder-list .ask-folder-item').forEach(function(item) {
|
|
1844
|
+
var p = item.dataset.path.toLowerCase();
|
|
1845
|
+
item.style.display = (!query || p.indexOf(query) !== -1) ? '' : 'none';
|
|
1846
|
+
});
|
|
1847
|
+
}
|
|
1848
|
+
function renderWikiAskSourcesPanel(context) {
|
|
1849
|
+
if (!context) return '';
|
|
1850
|
+
var sourcePaths = Array.isArray(context.source_paths) ? context.source_paths : [];
|
|
1851
|
+
var relationMap = context.truncated && typeof context.truncated === 'object' && context.truncated.relation ? context.truncated.relation : {};
|
|
1852
|
+
var total = sourcePaths.length;
|
|
1853
|
+
if (!total) return '';
|
|
1854
|
+
var rows = sourcePaths.map(function(p) {
|
|
1855
|
+
var rel = relationMap[p];
|
|
1856
|
+
var chipHtml;
|
|
1857
|
+
if (!rel || rel === 'primary') {
|
|
1858
|
+
chipHtml = '<span class="s-chip primary">primary</span>';
|
|
1859
|
+
} else {
|
|
1860
|
+
var facetsRaw = rel.replace(/^shares\s+/, '');
|
|
1861
|
+
var bkMatch = facetsRaw.match(/issue:([^,\s]+)/);
|
|
1862
|
+
var relLabel = bkMatch ? 'related \u00b7 ' + bkMatch[1] : 'related';
|
|
1863
|
+
chipHtml = '<span class="s-chip related">' + escapeHtml(relLabel) + '</span>';
|
|
1864
|
+
}
|
|
1865
|
+
return '<div class="ask-source-row"><span class="s-path">' + escapeHtml(p) + '</span>' + chipHtml + '</div>';
|
|
1866
|
+
}).join('');
|
|
1867
|
+
return '<div class="ask-sources"><button class="ask-sources-head" onclick="this.parentElement.classList.toggle(\'open\')" title="Toggle sources used panel"><span class="ask-sources-caret">►</span><span>Sources used</span><span class="ask-sources-badge">' + total + '</span></button><div class="ask-sources-body">' + rows + '</div></div>';
|
|
1868
|
+
}
|
|
1869
|
+
|
|
1438
1870
|
function getWikiAskVisibleDocIds() {
|
|
1439
1871
|
return getVisibleDocs().map(doc => doc.id);
|
|
1440
1872
|
}
|
|
@@ -1569,7 +2001,8 @@ function loadWikiAskHistoryItem(id) {
|
|
|
1569
2001
|
wikiAskState.question = '';
|
|
1570
2002
|
wikiAskState.pendingQuestion = '';
|
|
1571
2003
|
wikiAskState.lastQuestion = item.question || '';
|
|
1572
|
-
wikiAskState.mode = item.mode
|
|
2004
|
+
wikiAskState.mode = (item.mode === 'visible-group' ? 'all-docs' : (item.mode || 'all-docs'));
|
|
2005
|
+
wikiAskState.docPathFilter = item.doc_path_filter || '';
|
|
1573
2006
|
wikiAskState.selectedDocIds = Array.isArray(item.selected_doc_ids) ? [...item.selected_doc_ids] : [];
|
|
1574
2007
|
wikiAskState.answer = {
|
|
1575
2008
|
question: item.question || '',
|
|
@@ -1696,20 +2129,23 @@ function clearWikiAskSources() {
|
|
|
1696
2129
|
renderWikiAsk();
|
|
1697
2130
|
}
|
|
1698
2131
|
function getWikiAskSourceSummaryHtml() {
|
|
1699
|
-
const visibleCount = getWikiAskVisibleDocIds().length;
|
|
1700
2132
|
const selectedCount = wikiAskState.selectedDocIds.length;
|
|
1701
2133
|
const focusId = getGraphFocusId();
|
|
1702
|
-
const focusLabel = focusId ? ((docById[focusId] && (docById[focusId].title || focusId)) || focusId) :
|
|
2134
|
+
const focusLabel = focusId ? ((docById[focusId] && (docById[focusId].title || focusId)) || focusId) : null;
|
|
2135
|
+
if (wikiAskState.mode === 'all-docs') {
|
|
2136
|
+
const filteredIds = getWikiAskAllDocIds(wikiAskState.docPathFilter);
|
|
2137
|
+
if (wikiAskState.docPathFilter) {
|
|
2138
|
+
return `<strong>Scope:</strong> By folder <code>${escapeHtml(wikiAskState.docPathFilter)}</code> — ${filteredIds.length} of ${docs.length} docs.`;
|
|
2139
|
+
}
|
|
2140
|
+
return `<strong>Scope:</strong> All Docs — ${filteredIds.length} docs indexed.`;
|
|
2141
|
+
}
|
|
1703
2142
|
if (wikiAskState.mode === 'current-focus') {
|
|
1704
2143
|
if (focusId) {
|
|
1705
|
-
return `<strong>
|
|
2144
|
+
return `<strong>Scope:</strong> This doc + related — <strong>${escapeHtml(focusLabel)}</strong> and its related siblings.`;
|
|
1706
2145
|
}
|
|
1707
|
-
return `<strong>
|
|
1708
|
-
}
|
|
1709
|
-
if (wikiAskState.mode === 'visible-group') {
|
|
1710
|
-
return `<strong>Grounding:</strong> Visible graph group. <strong>Visible docs:</strong> ${visibleCount}.${selectedCount ? ` <strong>Explicit docs:</strong> ${selectedCount}.` : ''}`;
|
|
2146
|
+
return `<strong>Scope:</strong> This doc + related — <em>focus a graph node first.</em>`;
|
|
1711
2147
|
}
|
|
1712
|
-
return `<strong>
|
|
2148
|
+
return `<strong>Scope:</strong> Selected docs — ${selectedCount} doc${selectedCount !== 1 ? 's' : ''} attached.${selectedCount ? '' : ' Attach docs via @mention or graph search.'}`;
|
|
1713
2149
|
}
|
|
1714
2150
|
function getWikiAskAdvancedSummaryText() {
|
|
1715
2151
|
const bits = [];
|
|
@@ -1837,7 +2273,6 @@ function renderWikiAsk() {
|
|
|
1837
2273
|
);
|
|
1838
2274
|
const runtimeSelect = document.getElementById('atlas-ask-runtime-select');
|
|
1839
2275
|
const modelSelect = document.getElementById('atlas-ask-model-select');
|
|
1840
|
-
const modeSelect = document.getElementById('atlas-ask-mode-select');
|
|
1841
2276
|
const input = document.getElementById('atlas-ask-input');
|
|
1842
2277
|
const attachments = document.getElementById('atlas-ask-attachments');
|
|
1843
2278
|
const sourceSummary = document.getElementById('atlas-ask-source-summary');
|
|
@@ -1857,7 +2292,24 @@ function renderWikiAsk() {
|
|
|
1857
2292
|
modelSelect.innerHTML = modelOptions.map(model => `<option value="${model}">${escapeHtml(getWikiAskModelLabel(model))}</option>`).join('');
|
|
1858
2293
|
if (modelSelect.value !== wikiAskState.model) modelSelect.value = wikiAskState.model;
|
|
1859
2294
|
}
|
|
1860
|
-
|
|
2295
|
+
const scopeIco = document.getElementById('ask-scope-ico');
|
|
2296
|
+
const scopeLbl = document.getElementById('ask-scope-label');
|
|
2297
|
+
if (scopeIco && scopeLbl) {
|
|
2298
|
+
if (wikiAskState.mode === 'current-focus') {
|
|
2299
|
+
scopeIco.textContent = '\u{1F3AF}';
|
|
2300
|
+
scopeLbl.textContent = 'This doc + related';
|
|
2301
|
+
} else if (wikiAskState.mode === 'selected-docs') {
|
|
2302
|
+
scopeIco.textContent = '\u2713';
|
|
2303
|
+
const selCnt = wikiAskState.selectedDocIds.length;
|
|
2304
|
+
scopeLbl.textContent = selCnt > 0 ? `Selected docs (${selCnt})` : 'Selected docs';
|
|
2305
|
+
} else if (wikiAskState.docPathFilter) {
|
|
2306
|
+
scopeIco.textContent = '\u{1F4C1}';
|
|
2307
|
+
scopeLbl.textContent = wikiAskState.docPathFilter;
|
|
2308
|
+
} else {
|
|
2309
|
+
scopeIco.textContent = '\u{1F4DA}';
|
|
2310
|
+
scopeLbl.textContent = 'All Docs';
|
|
2311
|
+
}
|
|
2312
|
+
}
|
|
1861
2313
|
if (sourceSummary) sourceSummary.innerHTML = getWikiAskSourceSummaryHtml();
|
|
1862
2314
|
if (mentionResults) renderWikiAskMentions();
|
|
1863
2315
|
if (attachments) {
|
|
@@ -1903,7 +2355,8 @@ function renderWikiAsk() {
|
|
|
1903
2355
|
? `<ul>${turn.citations.map(item => `<li><button class="wiki-link" onclick="focusGraphNode('${item.path}')">${escapeHtml(item.title || item.path)}</button> · ${escapeHtml(item.reason || 'Grounded source')}</li>`).join('')}</ul>`
|
|
1904
2356
|
: '<p class="muted">No citations were returned.</p>';
|
|
1905
2357
|
blocks.push(`<div class="atlas-ask-message user"><div class="atlas-ask-message-label">You</div><div class="atlas-ask-message-bubble">${escapeHtml(turn.question || '')}</div></div>`);
|
|
1906
|
-
|
|
2358
|
+
const sourcesHtml = renderWikiAskSourcesPanel(turn.context || null);
|
|
2359
|
+
blocks.push(`<div class="atlas-ask-message assistant"><div class="atlas-ask-message-label">SDTK-WIKI Ask</div><div class="atlas-ask-answer-card"><div class="graph-note-prose">${renderMarkdownFragment(turn.answer_markdown || '')}</div>${turn.disclaimer ? `<span class="muted">${escapeHtml(turn.disclaimer)}</span>` : ''}</div><div class="atlas-ask-answer-card"><h3>Citations</h3>${citationHtml}</div>${sourcesHtml}</div>`);
|
|
1907
2360
|
});
|
|
1908
2361
|
|
|
1909
2362
|
if (wikiAskState.pendingQuestion) {
|
|
@@ -1912,7 +2365,7 @@ function renderWikiAsk() {
|
|
|
1912
2365
|
}
|
|
1913
2366
|
|
|
1914
2367
|
if (!blocks.length) {
|
|
1915
|
-
answer.innerHTML = '<div class="atlas-ask-empty">Ask
|
|
2368
|
+
answer.innerHTML = '<div class="atlas-ask-empty">Use <strong>Ask within</strong> to choose your scope: All Docs for full coverage, By folder to narrow by path, This doc + related to focus on the current graph node, or Selected docs for pinned sources.</div>';
|
|
1916
2369
|
return;
|
|
1917
2370
|
}
|
|
1918
2371
|
|
|
@@ -1930,14 +2383,18 @@ async function submitWikiAsk() {
|
|
|
1930
2383
|
renderWikiAsk();
|
|
1931
2384
|
return;
|
|
1932
2385
|
}
|
|
2386
|
+
const allDocIds = wikiAskState.mode === 'all-docs'
|
|
2387
|
+
? getWikiAskAllDocIds(wikiAskState.docPathFilter)
|
|
2388
|
+
: getWikiAskVisibleDocIds();
|
|
1933
2389
|
const payload = {
|
|
1934
2390
|
question: draftQuestion,
|
|
1935
2391
|
mode: wikiAskState.mode,
|
|
1936
2392
|
runtime_agent: wikiAskState.runtimeAgent,
|
|
1937
2393
|
model: wikiAskState.model,
|
|
1938
2394
|
focus_doc_id: getGraphFocusId() || '',
|
|
1939
|
-
visible_doc_ids:
|
|
2395
|
+
visible_doc_ids: allDocIds,
|
|
1940
2396
|
selected_doc_ids: [...wikiAskState.selectedDocIds],
|
|
2397
|
+
doc_path_filter: wikiAskState.mode === 'all-docs' ? (wikiAskState.docPathFilter || '') : '',
|
|
1941
2398
|
};
|
|
1942
2399
|
wikiAskState.pendingQuestion = draftQuestion;
|
|
1943
2400
|
wikiAskState.question = '';
|
|
@@ -2416,6 +2873,10 @@ document.addEventListener('mousedown', event => {
|
|
|
2416
2873
|
graphState.settingsOpen = false;
|
|
2417
2874
|
syncGraphSettings();
|
|
2418
2875
|
}
|
|
2876
|
+
const scopeWrap = document.getElementById('ask-scope-wrap');
|
|
2877
|
+
if (scopeWrap && scopeWrap.classList.contains('open') && !scopeWrap.contains(event.target)) {
|
|
2878
|
+
closeWikiAskScopeMenu();
|
|
2879
|
+
}
|
|
2419
2880
|
});
|
|
2420
2881
|
window.addEventListener('mousemove', dragWikiAsk);
|
|
2421
2882
|
window.addEventListener('mouseup', stopWikiAskDrag);
|