loki-mode 6.74.6 → 6.75.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/README.md +2 -54
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/loki +995 -0
- package/autonomy/run.sh +107 -2
- package/dashboard/__init__.py +1 -1
- package/docs/INSTALLATION.md +1 -1
- package/mcp/__init__.py +1 -1
- package/mcp/server.py +177 -0
- package/package.json +1 -1
- package/references/mcp-integration.md +59 -0
- package/skills/00-index.md +9 -0
- package/skills/documentation.md +123 -0
- package/skills/quality-gates.md +25 -1
- package/web-app/dist/assets/{AdminPage-Cwqm_kDg.js → AdminPage-D4QSV6Zi.js} +1 -1
- package/web-app/dist/assets/{Avatar-BgcFY2E5.js → Avatar-88MlpLO5.js} +1 -1
- package/web-app/dist/assets/{Badge-DeFGfZLB.js → Badge-DbGjLr4i.js} +1 -1
- package/web-app/dist/assets/{Button-Dg1EkPtN.js → Button-sp_FVGZj.js} +1 -1
- package/web-app/dist/assets/{ComparePage-D-wvMVP2.js → ComparePage-p2ENnfa7.js} +1 -1
- package/web-app/dist/assets/{GitHubIssuesPanel-B_Jm7CmJ.js → GitHubIssuesPanel-DBbBTG9w.js} +1 -1
- package/web-app/dist/assets/{GitHubPRsPanel-B5i8Q99N.js → GitHubPRsPanel-Bi_yrcAE.js} +1 -1
- package/web-app/dist/assets/{HomePage-CUDTdntY.js → HomePage-BB83YPiX.js} +1 -1
- package/web-app/dist/assets/{LoginPage-BobwVXx5.js → LoginPage-BXUudCJ9.js} +1 -1
- package/web-app/dist/assets/{MetricsPage-DmM--20B.js → MetricsPage-CX0Ahy-_.js} +1 -1
- package/web-app/dist/assets/{NotFoundPage-6_gjeogD.js → NotFoundPage-C4JqatEk.js} +1 -1
- package/web-app/dist/assets/{ProjectPage-C3R2wbFt.js → ProjectPage-t5J2XAJT.js} +46 -46
- package/web-app/dist/assets/{ProjectsPage-DQr06iBk.js → ProjectsPage-Bzpz1clk.js} +1 -1
- package/web-app/dist/assets/{SettingsPage-eROlGKB9.js → SettingsPage-y_yl8FvH.js} +1 -1
- package/web-app/dist/assets/{ShowcasePage-DEA5tT_R.js → ShowcasePage-B7d6pzMq.js} +1 -1
- package/web-app/dist/assets/{SystemSettingsPage-C_rIbgZg.js → SystemSettingsPage-C4tR33KU.js} +1 -1
- package/web-app/dist/assets/{TeamsPage-DZGoYZnD.js → TeamsPage-DIOCfZIP.js} +1 -1
- package/web-app/dist/assets/{TemplatesPage-DVblWpbO.js → TemplatesPage-DlKyapXX.js} +1 -1
- package/web-app/dist/assets/{TerminalOutput-DnESY9zk.js → TerminalOutput-Czg-ZC2k.js} +1 -1
- package/web-app/dist/assets/{activity-COLsZyo1.js → activity-h1wU9a0L.js} +1 -1
- package/web-app/dist/assets/{bell-BjLe9xXk.js → bell-Bu8lsWOp.js} +1 -1
- package/web-app/dist/assets/{bot-Dz62aBIi.js → bot-rWO7KjkQ.js} +1 -1
- package/web-app/dist/assets/{check-BQPQjkH4.js → check-BWp8L5Cy.js} +1 -1
- package/web-app/dist/assets/{chevron-left-BVvOVUQ8.js → chevron-left-Bw4I1yGm.js} +1 -1
- package/web-app/dist/assets/{circle-alert-DqoLW238.js → circle-alert-C37PKXiC.js} +1 -1
- package/web-app/dist/assets/{clock-Cn9fFUva.js → clock-DDScLol4.js} +1 -1
- package/web-app/dist/assets/{cloud-COJxbgUu.js → cloud-DaYKPLaM.js} +1 -1
- package/web-app/dist/assets/{copy-DOn0hVgy.js → copy-DKIRv0VK.js} +1 -1
- package/web-app/dist/assets/{database-Bj3Llvnk.js → database-CYZBHz51.js} +1 -1
- package/web-app/dist/assets/{dollar-sign-BcmncygQ.js → dollar-sign-CydJu0kl.js} +1 -1
- package/web-app/dist/assets/{file-code-corner-BysxoSyu.js → file-code-corner-DqZ9gpdv.js} +1 -1
- package/web-app/dist/assets/{file-plus-Dwi1MqSS.js → file-plus-CzeFJWp3.js} +1 -1
- package/web-app/dist/assets/{folder-open-WzXNCq2x.js → folder-open-4YWk08dP.js} +1 -1
- package/web-app/dist/assets/{git-commit-horizontal-D85UUfNF.js → git-commit-horizontal-wbqFPNID.js} +1 -1
- package/web-app/dist/assets/{globe-CegT0VaL.js → globe-Cby-g5Yb.js} +1 -1
- package/web-app/dist/assets/{hammer-ZGKvu_xy.js → hammer-BNScgGdp.js} +1 -1
- package/web-app/dist/assets/{index-_2iPl2nX.js → index-6Z4B0I6r.js} +74 -74
- package/web-app/dist/assets/{layers-B40lki5j.js → layers-XfssQc5V.js} +1 -1
- package/web-app/dist/assets/{lightbulb-CFSoqUsV.js → lightbulb-EhnzRw7M.js} +1 -1
- package/web-app/dist/assets/{loader-circle-womi7Brk.js → loader-circle-BA0QIVGA.js} +1 -1
- package/web-app/dist/assets/{lock-CEWBb_SL.js → lock-BABtHe6K.js} +1 -1
- package/web-app/dist/assets/{mail-DimGrYf8.js → mail-Dokiey5S.js} +1 -1
- package/web-app/dist/assets/{package-DysIuuIJ.js → package-DbJyS1Ft.js} +1 -1
- package/web-app/dist/assets/{plus-DG1hW27_.js → plus-BcAN8Kaj.js} +1 -1
- package/web-app/dist/assets/{refresh-cw-X31ig0S6.js → refresh-cw-B3dG1-Sb.js} +1 -1
- package/web-app/dist/assets/{rotate-ccw-CBXooICo.js → rotate-ccw-Cs1Phctm.js} +1 -1
- package/web-app/dist/assets/{save-DQVrWTjZ.js → save-DsrNCZrP.js} +1 -1
- package/web-app/dist/assets/{server-BYAMALfa.js → server-CpN2GX4G.js} +1 -1
- package/web-app/dist/assets/{shield-alert-B3G7vLiW.js → shield-alert-CKJ1pzCz.js} +1 -1
- package/web-app/dist/assets/{trash-2-ChVunC-C.js → trash-2-C9vZqTqw.js} +1 -1
- package/web-app/dist/assets/{trending-down-DgsuOE2t.js → trending-down-BNLTrF5P.js} +1 -1
- package/web-app/dist/assets/{trending-up-CZHZsGeN.js → trending-up-DmFIdVOc.js} +1 -1
- package/web-app/dist/assets/{usePolling-ns_dFCVn.js → usePolling-vUlY-o6P.js} +1 -1
- package/web-app/dist/assets/{user-FQUrWHhF.js → user-Dh00W8De.js} +1 -1
- package/web-app/dist/index.html +1 -1
- package/web-app/server.py +196 -0
package/autonomy/run.sh
CHANGED
|
@@ -2545,7 +2545,8 @@ merge_feature() {
|
|
|
2545
2545
|
# Delete branch
|
|
2546
2546
|
git -C "$TARGET_DIR" branch -d "$branch" 2>/dev/null || true
|
|
2547
2547
|
|
|
2548
|
-
#
|
|
2548
|
+
# DOCS_NEEDED signal: triggers the parallel docs worktree to run `loki docs update`
|
|
2549
|
+
# and regenerate documentation for recently changed files.
|
|
2549
2550
|
mkdir -p "$TARGET_DIR/.loki/signals"
|
|
2550
2551
|
touch "$TARGET_DIR/.loki/signals/DOCS_NEEDED"
|
|
2551
2552
|
}
|
|
@@ -2655,7 +2656,7 @@ run_parallel_orchestrator() {
|
|
|
2655
2656
|
|
|
2656
2657
|
# Spawn docs session
|
|
2657
2658
|
if [ "$PARALLEL_DOCS" = "true" ] && [ -n "${WORKTREE_PATHS[docs]:-}" ]; then
|
|
2658
|
-
spawn_worktree_session "docs" "
|
|
2659
|
+
spawn_worktree_session "docs" "Documentation maintenance stream. Steps: 1) Run 'loki docs generate' if .loki/docs/ does not exist. 2) Watch for .loki/signals/DOCS_NEEDED file. When found, run 'loki docs update' and remove the signal file. 3) After each doc update, run 'loki docs check' and report coverage. 4) Focus on documenting new files, changed APIs, and architectural decisions."
|
|
2659
2660
|
fi
|
|
2660
2661
|
|
|
2661
2662
|
# Main orchestrator loop
|
|
@@ -5695,6 +5696,94 @@ TREOF
|
|
|
5695
5696
|
fi
|
|
5696
5697
|
}
|
|
5697
5698
|
|
|
5699
|
+
# ============================================================================
|
|
5700
|
+
# Documentation Staleness Check (v6.75.0)
|
|
5701
|
+
# Checks if generated documentation is stale relative to HEAD
|
|
5702
|
+
# ============================================================================
|
|
5703
|
+
|
|
5704
|
+
run_doc_staleness_check() {
|
|
5705
|
+
local manifest="$TARGET_DIR/.loki/docs/docs-manifest.json"
|
|
5706
|
+
if [ ! -f "$manifest" ]; then
|
|
5707
|
+
log_info "Documentation: No docs generated yet (run 'loki docs generate')"
|
|
5708
|
+
return 0
|
|
5709
|
+
fi
|
|
5710
|
+
|
|
5711
|
+
local doc_sha
|
|
5712
|
+
doc_sha=$(python3 -c "import json; print(json.load(open('$manifest')).get('git_sha', ''))" 2>/dev/null)
|
|
5713
|
+
if [ -z "$doc_sha" ]; then
|
|
5714
|
+
return 0
|
|
5715
|
+
fi
|
|
5716
|
+
|
|
5717
|
+
local commits_behind
|
|
5718
|
+
commits_behind=$(git -C "${TARGET_DIR:-.}" rev-list --count "$doc_sha..HEAD" 2>/dev/null || echo "0")
|
|
5719
|
+
|
|
5720
|
+
if [ "$commits_behind" -gt 10 ]; then
|
|
5721
|
+
log_warn "Documentation is $commits_behind commits behind. Consider running 'loki docs update'."
|
|
5722
|
+
# Emit DOCS_NEEDED signal for the parallel docs worktree
|
|
5723
|
+
mkdir -p "$TARGET_DIR/.loki/signals"
|
|
5724
|
+
touch "$TARGET_DIR/.loki/signals/DOCS_NEEDED"
|
|
5725
|
+
else
|
|
5726
|
+
log_info "Documentation: up to date ($commits_behind commits since last update)"
|
|
5727
|
+
fi
|
|
5728
|
+
}
|
|
5729
|
+
|
|
5730
|
+
# ============================================================================
|
|
5731
|
+
# Documentation Quality Gate - Gate 11 (v6.75.0)
|
|
5732
|
+
# Checks README, documentation freshness, and package API docs
|
|
5733
|
+
# ============================================================================
|
|
5734
|
+
|
|
5735
|
+
run_doc_quality_gate() {
|
|
5736
|
+
# shellcheck disable=SC2120
|
|
5737
|
+
local project_dir="${1:-${TARGET_DIR:-.}}"
|
|
5738
|
+
local score=100
|
|
5739
|
+
local issues=()
|
|
5740
|
+
|
|
5741
|
+
# Check 1: README.md exists
|
|
5742
|
+
if [ ! -f "$project_dir/README.md" ] || [ ! -s "$project_dir/README.md" ]; then
|
|
5743
|
+
score=$((score - 20))
|
|
5744
|
+
issues+=("README.md missing or empty")
|
|
5745
|
+
fi
|
|
5746
|
+
|
|
5747
|
+
# Check 2: Documentation freshness
|
|
5748
|
+
local manifest="$project_dir/.loki/docs/docs-manifest.json"
|
|
5749
|
+
if [ -f "$manifest" ]; then
|
|
5750
|
+
local doc_sha
|
|
5751
|
+
doc_sha=$(python3 -c "import json; print(json.load(open('$manifest')).get('git_sha', ''))" 2>/dev/null)
|
|
5752
|
+
if [ -n "$doc_sha" ]; then
|
|
5753
|
+
local behind
|
|
5754
|
+
behind=$(git -C "$project_dir" rev-list --count "$doc_sha..HEAD" 2>/dev/null || echo "0")
|
|
5755
|
+
if [ "$behind" -gt 10 ]; then
|
|
5756
|
+
score=$((score - 15))
|
|
5757
|
+
issues+=("Documentation is $behind commits behind HEAD")
|
|
5758
|
+
fi
|
|
5759
|
+
fi
|
|
5760
|
+
else
|
|
5761
|
+
score=$((score - 10))
|
|
5762
|
+
issues+=("No generated documentation found (run 'loki docs generate')")
|
|
5763
|
+
fi
|
|
5764
|
+
|
|
5765
|
+
# Check 3: Package documentation (for npm/pip packages)
|
|
5766
|
+
if [ -f "$project_dir/package.json" ] || [ -f "$project_dir/setup.py" ] || [ -f "$project_dir/pyproject.toml" ]; then
|
|
5767
|
+
if [ ! -f "$project_dir/.loki/docs/API.md" ]; then
|
|
5768
|
+
score=$((score - 15))
|
|
5769
|
+
issues+=("Package detected but no API documentation generated")
|
|
5770
|
+
fi
|
|
5771
|
+
fi
|
|
5772
|
+
|
|
5773
|
+
# Report
|
|
5774
|
+
if [ ${#issues[@]} -gt 0 ]; then
|
|
5775
|
+
log_warn "Documentation Gate: Score $score/100"
|
|
5776
|
+
for issue in "${issues[@]}"; do
|
|
5777
|
+
log_warn " - $issue"
|
|
5778
|
+
done
|
|
5779
|
+
else
|
|
5780
|
+
log_info "Documentation Gate: PASS (Score $score/100)"
|
|
5781
|
+
fi
|
|
5782
|
+
|
|
5783
|
+
# Gate passes if score >= 70
|
|
5784
|
+
[ "$score" -ge 70 ]
|
|
5785
|
+
}
|
|
5786
|
+
|
|
5698
5787
|
# ============================================================================
|
|
5699
5788
|
# 3-Reviewer Parallel Code Review (v5.35.0)
|
|
5700
5789
|
# Specialist pool from skills/quality-gates.md with blind review
|
|
@@ -9982,6 +10071,22 @@ if __name__ == "__main__":
|
|
|
9982
10071
|
fi
|
|
9983
10072
|
fi
|
|
9984
10073
|
fi
|
|
10074
|
+
# Documentation staleness check (v6.75.0)
|
|
10075
|
+
if [ "$ITERATION_COUNT" -gt 0 ]; then
|
|
10076
|
+
run_doc_staleness_check
|
|
10077
|
+
fi
|
|
10078
|
+
# Documentation quality gate - Gate 11 (v6.75.0)
|
|
10079
|
+
if [ "${LOKI_GATE_DOC_COVERAGE:-true}" = "true" ] && [ "$ITERATION_COUNT" -gt 0 ]; then
|
|
10080
|
+
log_info "Quality gate: documentation coverage..."
|
|
10081
|
+
if run_doc_quality_gate; then
|
|
10082
|
+
clear_gate_failure "doc_coverage"
|
|
10083
|
+
else
|
|
10084
|
+
local dc_count
|
|
10085
|
+
dc_count=$(track_gate_failure "doc_coverage")
|
|
10086
|
+
gate_failures="${gate_failures}doc_coverage,"
|
|
10087
|
+
log_warn "Documentation coverage gate: Score below threshold ($dc_count consecutive)"
|
|
10088
|
+
fi
|
|
10089
|
+
fi
|
|
9985
10090
|
# Store gate failures for prompt injection
|
|
9986
10091
|
if [ -n "$gate_failures" ]; then
|
|
9987
10092
|
echo "$gate_failures" > "${TARGET_DIR:-.}/.loki/quality/gate-failures.txt"
|
package/dashboard/__init__.py
CHANGED
package/docs/INSTALLATION.md
CHANGED
package/mcp/__init__.py
CHANGED
package/mcp/server.py
CHANGED
|
@@ -1739,6 +1739,183 @@ async def mem_get(
|
|
|
1739
1739
|
return json.dumps({"error": str(e), "entries": {}})
|
|
1740
1740
|
|
|
1741
1741
|
|
|
1742
|
+
# ============================================================
|
|
1743
|
+
# GIT INTELLIGENCE TOOLS (Phase 4 - Repowise native equivalent)
|
|
1744
|
+
# ============================================================
|
|
1745
|
+
|
|
1746
|
+
@mcp.tool()
|
|
1747
|
+
async def loki_get_hotspots(
|
|
1748
|
+
limit: int = 10,
|
|
1749
|
+
) -> str:
|
|
1750
|
+
"""Get the most frequently changed files in the repository.
|
|
1751
|
+
|
|
1752
|
+
Identifies code hotspots based on git commit frequency analysis.
|
|
1753
|
+
These files deserve extra care during changes (higher risk of regressions).
|
|
1754
|
+
|
|
1755
|
+
Args:
|
|
1756
|
+
limit: Number of top hotspot files to return (default 10, max 30)
|
|
1757
|
+
"""
|
|
1758
|
+
_emit_tool_event_async('loki_get_hotspots', 'start',
|
|
1759
|
+
parameters={'limit': limit})
|
|
1760
|
+
|
|
1761
|
+
limit = min(max(1, limit), 30)
|
|
1762
|
+
|
|
1763
|
+
try:
|
|
1764
|
+
hotspots_path = safe_path_join('.loki', 'intelligence', 'hotspots.txt')
|
|
1765
|
+
except PathTraversalError:
|
|
1766
|
+
_emit_tool_event_async('loki_get_hotspots', 'complete',
|
|
1767
|
+
result_status='error', error='Access denied')
|
|
1768
|
+
return json.dumps({"error": "Access denied"})
|
|
1769
|
+
|
|
1770
|
+
if not os.path.exists(hotspots_path):
|
|
1771
|
+
_emit_tool_event_async('loki_get_hotspots', 'complete',
|
|
1772
|
+
result_status='error', error='Not available')
|
|
1773
|
+
return json.dumps({
|
|
1774
|
+
"error": "Git intelligence not yet generated",
|
|
1775
|
+
"hint": "Run 'loki start' or wait for the next autonomous iteration"
|
|
1776
|
+
})
|
|
1777
|
+
|
|
1778
|
+
try:
|
|
1779
|
+
results = []
|
|
1780
|
+
with open(hotspots_path, 'r') as f:
|
|
1781
|
+
for line in f:
|
|
1782
|
+
line = line.strip()
|
|
1783
|
+
if not line:
|
|
1784
|
+
continue
|
|
1785
|
+
# Format: " 42 path/to/file.py"
|
|
1786
|
+
parts = line.split(None, 1)
|
|
1787
|
+
if len(parts) == 2:
|
|
1788
|
+
try:
|
|
1789
|
+
changes = int(parts[0])
|
|
1790
|
+
except ValueError:
|
|
1791
|
+
continue
|
|
1792
|
+
results.append({"file": parts[1], "changes": changes})
|
|
1793
|
+
if len(results) >= limit:
|
|
1794
|
+
break
|
|
1795
|
+
|
|
1796
|
+
_emit_tool_event_async('loki_get_hotspots', 'complete',
|
|
1797
|
+
result_status='success', result_count=len(results))
|
|
1798
|
+
return json.dumps({"hotspots": results, "total": len(results)})
|
|
1799
|
+
except Exception as e:
|
|
1800
|
+
logger.error(f"loki_get_hotspots failed: {e}")
|
|
1801
|
+
_emit_tool_event_async('loki_get_hotspots', 'complete',
|
|
1802
|
+
result_status='error', error=str(e))
|
|
1803
|
+
return json.dumps({"error": str(e)})
|
|
1804
|
+
|
|
1805
|
+
|
|
1806
|
+
@mcp.tool()
|
|
1807
|
+
async def loki_get_co_changes(
|
|
1808
|
+
file_path: str,
|
|
1809
|
+
) -> str:
|
|
1810
|
+
"""Find files that frequently change together with a given file.
|
|
1811
|
+
|
|
1812
|
+
Uses git co-change analysis to identify coupling between files.
|
|
1813
|
+
Useful for understanding hidden dependencies and ensuring related
|
|
1814
|
+
files are updated together.
|
|
1815
|
+
|
|
1816
|
+
Args:
|
|
1817
|
+
file_path: Path to the file to find co-change partners for
|
|
1818
|
+
"""
|
|
1819
|
+
_emit_tool_event_async('loki_get_co_changes', 'start',
|
|
1820
|
+
parameters={'file_path': file_path})
|
|
1821
|
+
|
|
1822
|
+
try:
|
|
1823
|
+
co_changes_path = safe_path_join('.loki', 'intelligence', 'co-changes.json')
|
|
1824
|
+
except PathTraversalError:
|
|
1825
|
+
_emit_tool_event_async('loki_get_co_changes', 'complete',
|
|
1826
|
+
result_status='error', error='Access denied')
|
|
1827
|
+
return json.dumps({"error": "Access denied"})
|
|
1828
|
+
|
|
1829
|
+
if not os.path.exists(co_changes_path):
|
|
1830
|
+
_emit_tool_event_async('loki_get_co_changes', 'complete',
|
|
1831
|
+
result_status='error', error='Not available')
|
|
1832
|
+
return json.dumps({
|
|
1833
|
+
"error": "Git intelligence not yet generated",
|
|
1834
|
+
"hint": "Run 'loki start' or wait for the next autonomous iteration"
|
|
1835
|
+
})
|
|
1836
|
+
|
|
1837
|
+
try:
|
|
1838
|
+
with open(co_changes_path, 'r') as f:
|
|
1839
|
+
pairs = json.load(f)
|
|
1840
|
+
|
|
1841
|
+
# Filter pairs involving the requested file
|
|
1842
|
+
results = []
|
|
1843
|
+
for pair_files, count in pairs:
|
|
1844
|
+
if file_path in pair_files:
|
|
1845
|
+
partner = pair_files[0] if pair_files[1] == file_path else pair_files[1]
|
|
1846
|
+
results.append({"partner": partner, "co_changes": count})
|
|
1847
|
+
|
|
1848
|
+
# Sort by co-change count descending
|
|
1849
|
+
results.sort(key=lambda x: x["co_changes"], reverse=True)
|
|
1850
|
+
|
|
1851
|
+
_emit_tool_event_async('loki_get_co_changes', 'complete',
|
|
1852
|
+
result_status='success', result_count=len(results))
|
|
1853
|
+
return json.dumps({
|
|
1854
|
+
"file": file_path,
|
|
1855
|
+
"co_changed_with": results,
|
|
1856
|
+
"total": len(results)
|
|
1857
|
+
})
|
|
1858
|
+
except Exception as e:
|
|
1859
|
+
logger.error(f"loki_get_co_changes failed: {e}")
|
|
1860
|
+
_emit_tool_event_async('loki_get_co_changes', 'complete',
|
|
1861
|
+
result_status='error', error=str(e))
|
|
1862
|
+
return json.dumps({"error": str(e)})
|
|
1863
|
+
|
|
1864
|
+
|
|
1865
|
+
@mcp.tool()
|
|
1866
|
+
async def loki_get_doc_coverage() -> str:
|
|
1867
|
+
"""Get documentation coverage status for the project.
|
|
1868
|
+
|
|
1869
|
+
Reads from the docs manifest to report which files are documented,
|
|
1870
|
+
which have stale documentation, and which are missing docs entirely.
|
|
1871
|
+
Useful for prioritizing documentation work.
|
|
1872
|
+
"""
|
|
1873
|
+
_emit_tool_event_async('loki_get_doc_coverage', 'start')
|
|
1874
|
+
|
|
1875
|
+
try:
|
|
1876
|
+
manifest_path = safe_path_join('.loki', 'docs', 'docs-manifest.json')
|
|
1877
|
+
except PathTraversalError:
|
|
1878
|
+
_emit_tool_event_async('loki_get_doc_coverage', 'complete',
|
|
1879
|
+
result_status='error', error='Access denied')
|
|
1880
|
+
return json.dumps({"error": "Access denied"})
|
|
1881
|
+
|
|
1882
|
+
if not os.path.exists(manifest_path):
|
|
1883
|
+
_emit_tool_event_async('loki_get_doc_coverage', 'complete',
|
|
1884
|
+
result_status='error', error='Not available')
|
|
1885
|
+
return json.dumps({
|
|
1886
|
+
"error": "Documentation manifest not found",
|
|
1887
|
+
"hint": "Create .loki/docs/docs-manifest.json with file documentation status"
|
|
1888
|
+
})
|
|
1889
|
+
|
|
1890
|
+
try:
|
|
1891
|
+
with open(manifest_path, 'r') as f:
|
|
1892
|
+
manifest = json.load(f)
|
|
1893
|
+
|
|
1894
|
+
total_files = manifest.get("total_files", 0)
|
|
1895
|
+
documented_files = manifest.get("documented_files", 0)
|
|
1896
|
+
coverage_pct = round((documented_files / total_files * 100) if total_files > 0 else 0, 1)
|
|
1897
|
+
|
|
1898
|
+
stale_docs = manifest.get("stale_docs", [])
|
|
1899
|
+
missing_docs = manifest.get("missing_docs", [])
|
|
1900
|
+
|
|
1901
|
+
result = {
|
|
1902
|
+
"coverage_pct": coverage_pct,
|
|
1903
|
+
"total_files": total_files,
|
|
1904
|
+
"documented_files": documented_files,
|
|
1905
|
+
"stale_docs": stale_docs[:20], # Limit to avoid huge responses
|
|
1906
|
+
"missing_docs": missing_docs[:20],
|
|
1907
|
+
}
|
|
1908
|
+
|
|
1909
|
+
_emit_tool_event_async('loki_get_doc_coverage', 'complete',
|
|
1910
|
+
result_status='success')
|
|
1911
|
+
return json.dumps(result)
|
|
1912
|
+
except Exception as e:
|
|
1913
|
+
logger.error(f"loki_get_doc_coverage failed: {e}")
|
|
1914
|
+
_emit_tool_event_async('loki_get_doc_coverage', 'complete',
|
|
1915
|
+
result_status='error', error=str(e))
|
|
1916
|
+
return json.dumps({"error": str(e)})
|
|
1917
|
+
|
|
1918
|
+
|
|
1742
1919
|
# ============================================================
|
|
1743
1920
|
# PROMPTS - Pre-built prompt templates
|
|
1744
1921
|
# ============================================================
|
package/package.json
CHANGED
|
@@ -93,6 +93,60 @@ Model Context Protocol (MCP) servers extend Claude Code's capabilities with spec
|
|
|
93
93
|
|
|
94
94
|
---
|
|
95
95
|
|
|
96
|
+
### 3. Repowise - Codebase Intelligence (Recommended)
|
|
97
|
+
|
|
98
|
+
**Purpose:** Deep codebase intelligence through 8 MCP tools. When installed, Loki Mode automatically uses its tools for richer context during builds.
|
|
99
|
+
|
|
100
|
+
**When to use:**
|
|
101
|
+
- First encounter with an unfamiliar codebase
|
|
102
|
+
- Before modifying files with many dependents
|
|
103
|
+
- Architecture documentation and decision history
|
|
104
|
+
- Semantic code search (natural language)
|
|
105
|
+
|
|
106
|
+
**Setup:**
|
|
107
|
+
```bash
|
|
108
|
+
pip install repowise
|
|
109
|
+
repowise init . # One-time indexing (~25 min)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Configuration:**
|
|
113
|
+
```json
|
|
114
|
+
{
|
|
115
|
+
"mcpServers": {
|
|
116
|
+
"repowise": {
|
|
117
|
+
"command": "repowise",
|
|
118
|
+
"args": ["mcp", "--path", "."]
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Tools provided:**
|
|
125
|
+
|
|
126
|
+
| Tool | Purpose | Use Case |
|
|
127
|
+
|------|---------|----------|
|
|
128
|
+
| `get_overview()` | Architecture summary | First call on unfamiliar codebase |
|
|
129
|
+
| `get_context(targets)` | Docs, ownership, decisions | Before modifying files |
|
|
130
|
+
| `get_risk(targets)` | Hotspots, dependents, co-changes | Before modifying files |
|
|
131
|
+
| `get_why(query)` | Decision history | Before architectural changes |
|
|
132
|
+
| `search_codebase(query)` | Natural language code search | Finding code semantically |
|
|
133
|
+
| `get_dependency_path(from, to)` | Trace connections between files | Dependency analysis |
|
|
134
|
+
| `get_dead_code()` | Find unreachable code | Cleanup and refactoring |
|
|
135
|
+
| `get_architecture_diagram(module)` | Generate Mermaid diagrams | Documentation generation |
|
|
136
|
+
|
|
137
|
+
**SDLC Phases:** Bootstrap (overview), Development (context/risk), Documentation (diagrams)
|
|
138
|
+
|
|
139
|
+
**Integration with Loki Mode:**
|
|
140
|
+
When Repowise MCP is detected (via `.claude/mcp.json`), Loki Mode automatically:
|
|
141
|
+
1. Calls `get_overview()` during the BOOTSTRAP phase
|
|
142
|
+
2. Calls `get_risk()` before modifying hotspot files
|
|
143
|
+
3. Calls `get_context()` when loading relevant file context
|
|
144
|
+
4. Uses `search_codebase()` instead of manual grep for semantic code search
|
|
145
|
+
|
|
146
|
+
See `skills/documentation.md` for documentation generation using Repowise.
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
96
150
|
## MCP Configuration Location
|
|
97
151
|
|
|
98
152
|
Claude Code reads MCP configuration from:
|
|
@@ -114,6 +168,10 @@ Example full configuration:
|
|
|
114
168
|
"env": {
|
|
115
169
|
"PARALLEL_API_KEY": "${PARALLEL_API_KEY}"
|
|
116
170
|
}
|
|
171
|
+
},
|
|
172
|
+
"repowise": {
|
|
173
|
+
"command": "repowise",
|
|
174
|
+
"args": ["mcp", "--path", "."]
|
|
117
175
|
}
|
|
118
176
|
}
|
|
119
177
|
}
|
|
@@ -184,3 +242,4 @@ When evaluating new MCP servers for Loki Mode integration, assess:
|
|
|
184
242
|
- [MCP Specification](https://modelcontextprotocol.io/)
|
|
185
243
|
- [Parallel AI Documentation](https://docs.parallel.ai/)
|
|
186
244
|
- [Playwright MCP](https://github.com/anthropics/anthropic-quickstarts/tree/main/mcp-playwright)
|
|
245
|
+
- [Repowise](https://repowise.dev/)
|
package/skills/00-index.md
CHANGED
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
| Multi-provider (Codex, Gemini) | `providers.md` |
|
|
30
30
|
| OpenSpec delta context, brownfield modifications | `openspec-integration.md` |
|
|
31
31
|
| MiroFish market validation, `--mirofish` flag | `mirofish-integration.md` |
|
|
32
|
+
| Writing/updating documentation, `loki docs` | `documentation.md` |
|
|
32
33
|
| Legacy healing, modernization, archaeology | `healing.md` |
|
|
33
34
|
| Plan deepening, knowledge extraction | `compound-learning.md` |
|
|
34
35
|
|
|
@@ -127,6 +128,14 @@
|
|
|
127
128
|
- Risk-driven task ordering
|
|
128
129
|
- Advisory-only (never gates RARV or Completion Council)
|
|
129
130
|
|
|
131
|
+
### documentation.md
|
|
132
|
+
**When:** Writing/updating documentation, `loki docs` commands, Repowise MCP available
|
|
133
|
+
- Documentation types (README, ARCHITECTURE, API, DECISIONS, etc.)
|
|
134
|
+
- Model selection for doc generation (Sonnet/Haiku/Opus)
|
|
135
|
+
- Repowise MCP integration for codebase intelligence
|
|
136
|
+
- Documentation quality criteria and prompts
|
|
137
|
+
- Fallback to native git analysis when Repowise unavailable
|
|
138
|
+
|
|
130
139
|
### compound-learning.md (v5.30.0)
|
|
131
140
|
**When:** After architecture phase (deepen plan), after verification (extract learnings)
|
|
132
141
|
- Deepen-plan: 4 parallel research agents enhance plans before implementation
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Documentation Skill Module
|
|
2
|
+
|
|
3
|
+
## Research Foundation
|
|
4
|
+
|
|
5
|
+
| Source | Key Contribution | Citation |
|
|
6
|
+
|--------|-----------------|----------|
|
|
7
|
+
| Repowise | Codebase intelligence via MCP tools (overview, risk, context, search) | [repowise.dev](https://repowise.dev/) |
|
|
8
|
+
| Diátaxis | Documentation system: tutorials, how-to, reference, explanation | [diataxis.fr](https://diataxis.fr/) |
|
|
9
|
+
| Google Developer Docs | Style guide for technical documentation | [developers.google.com/style](https://developers.google.com/style) |
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## When to Load This Module
|
|
14
|
+
|
|
15
|
+
- Writing or updating documentation
|
|
16
|
+
- Running `loki docs` commands
|
|
17
|
+
- After build completion for doc generation
|
|
18
|
+
- When Repowise MCP is available
|
|
19
|
+
- Architecture documentation tasks
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Documentation Types
|
|
24
|
+
|
|
25
|
+
| Type | Description | Trigger |
|
|
26
|
+
|------|-------------|---------|
|
|
27
|
+
| README.md | Project overview, setup, usage | New project or major changes |
|
|
28
|
+
| ARCHITECTURE.md | System design, data flow | Architecture phase |
|
|
29
|
+
| API.md | Public API reference | API changes |
|
|
30
|
+
| SETUP.md | Dev environment setup | Dependency changes |
|
|
31
|
+
| COMPONENTS.md | Per-component docs | New components |
|
|
32
|
+
| TESTING.md | Test strategy, coverage | Test changes |
|
|
33
|
+
| DECISIONS.md | Architectural decisions | Design decisions made |
|
|
34
|
+
| CLAUDE.md | AI agent context | Every iteration |
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Model Selection
|
|
39
|
+
|
|
40
|
+
- **Documentation generation:** Sonnet (standard tier)
|
|
41
|
+
- **Doc checking/validation:** Haiku (fast tier)
|
|
42
|
+
- **Architecture documentation:** Opus (planning tier)
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Repowise Integration
|
|
47
|
+
|
|
48
|
+
When Repowise MCP tools are available (check tool list for `get_overview`, `get_context`, `get_risk`):
|
|
49
|
+
|
|
50
|
+
1. Prefer Repowise tools over native file scanning for context gathering
|
|
51
|
+
2. Use `get_overview()` as the foundation for ARCHITECTURE.md
|
|
52
|
+
3. Use `get_risk()` to prioritize which components need documentation most
|
|
53
|
+
4. Use `search_codebase()` for finding related code when documenting
|
|
54
|
+
5. Use `get_architecture_diagram(module)` for generating Mermaid component diagrams
|
|
55
|
+
6. Use `get_why(query)` to populate DECISIONS.md with architectural rationale
|
|
56
|
+
|
|
57
|
+
When Repowise is NOT available:
|
|
58
|
+
|
|
59
|
+
1. Fall back to native git analysis (`loki docs generate`)
|
|
60
|
+
2. Use file tree scanning for context
|
|
61
|
+
3. Use `git log` for change history
|
|
62
|
+
|
|
63
|
+
### Detection
|
|
64
|
+
|
|
65
|
+
Repowise MCP is detected automatically when `.claude/mcp.json` contains a `repowise` server entry. Loki Mode injects Repowise instructions into the build prompt when detected.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Documentation Quality Criteria
|
|
70
|
+
|
|
71
|
+
- **Accuracy:** Matches current code behavior
|
|
72
|
+
- **Completeness:** All public APIs documented
|
|
73
|
+
- **Freshness:** Updated within 10 commits of code changes
|
|
74
|
+
- **Readability:** Clear, concise, follows project conventions
|
|
75
|
+
- **Actionable:** Setup docs enable a new developer to start in <10 min
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Prompts
|
|
80
|
+
|
|
81
|
+
### For README generation
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
Analyze this project and generate a comprehensive README.md. Include: project name,
|
|
85
|
+
description, features, quick start, installation, usage examples, configuration,
|
|
86
|
+
API reference summary, contributing guidelines, and license. Be concise and practical.
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### For ARCHITECTURE generation
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
Analyze this project's architecture. Document: system overview, component diagram
|
|
93
|
+
(mermaid), data flow, key design decisions, tech stack rationale, deployment
|
|
94
|
+
architecture, and scaling considerations. Focus on WHY decisions were made, not
|
|
95
|
+
just WHAT exists.
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### For API documentation
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
Document all public APIs in this project. For each endpoint/function/class:
|
|
102
|
+
signature, parameters with types, return values, examples, error cases. Group by
|
|
103
|
+
module/route. Include curl examples for HTTP APIs.
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### For DECISIONS documentation
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
Review git history and code comments for architectural decisions. For each decision:
|
|
110
|
+
context (what problem was being solved), decision (what was chosen), rationale
|
|
111
|
+
(why this option), alternatives considered, and consequences. Use ADR format.
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Integration with Other Skills
|
|
117
|
+
|
|
118
|
+
| Skill | Interaction |
|
|
119
|
+
|-------|-------------|
|
|
120
|
+
| `quality-gates.md` | Gate 7 checks documentation freshness |
|
|
121
|
+
| `artifacts.md` | Documentation generation uses artifact patterns |
|
|
122
|
+
| `healing.md` | Healing archaeology feeds into institutional knowledge docs |
|
|
123
|
+
| `agents.md` | `documentation-writer` agent type for parallel doc generation |
|
package/skills/quality-gates.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**Never ship code without passing all quality gates.**
|
|
4
4
|
|
|
5
|
-
## The
|
|
5
|
+
## The 11 Quality Gates
|
|
6
6
|
|
|
7
7
|
1. **Input Guardrails** - Validate scope, detect injection, check constraints (OpenAI SDK)
|
|
8
8
|
2. **Static Analysis** - CodeQL, ESLint/Pylint, type checking
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
8. **Mock Detector** - Classifies internal vs external mocks; flags tests that never import source code, tautological assertions, and high internal mock ratios
|
|
15
15
|
9. **Test Mutation Detector** - Detects assertion value changes alongside implementation changes (test fitting), low assertion density, and missing pass/fail tracking
|
|
16
16
|
10. **Backward Compatibility** - Behavioral preservation, friction safety, institutional knowledge retention (healing mode)
|
|
17
|
+
11. **Documentation Coverage** - README exists, docs freshness within 10 commits, API docs for packages
|
|
17
18
|
|
|
18
19
|
## Gate 10: Backward Compatibility & Behavioral Preservation (v6.67.0)
|
|
19
20
|
|
|
@@ -42,6 +43,29 @@ LOKI_GATE_BACKWARD_COMPAT=false # Disable gate 10
|
|
|
42
43
|
|
|
43
44
|
---
|
|
44
45
|
|
|
46
|
+
## Gate 11: Documentation Coverage (v6.75.0)
|
|
47
|
+
|
|
48
|
+
**Triggers when:** Diff touches public APIs, new files added, library/package releases
|
|
49
|
+
|
|
50
|
+
**Checks:**
|
|
51
|
+
- Every exported function/class/endpoint has a doc entry in `.loki/docs/`
|
|
52
|
+
- README.md exists and is non-empty in project root
|
|
53
|
+
- Documentation SHA is within 10 commits of HEAD
|
|
54
|
+
- CLAUDE.md (if exists) references current key files
|
|
55
|
+
|
|
56
|
+
**Severity:**
|
|
57
|
+
- Missing API docs = Medium (BLOCK for npm/pip packages)
|
|
58
|
+
- Stale docs = Low (TODO)
|
|
59
|
+
|
|
60
|
+
**Skip:** Internal-only changes, test-only changes, config changes
|
|
61
|
+
|
|
62
|
+
**Disabling (not recommended for packages):**
|
|
63
|
+
```bash
|
|
64
|
+
LOKI_GATE_DOC_COVERAGE=false # Disable gate 11
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
45
69
|
## Gate 8 and 9: Automated Test Integrity
|
|
46
70
|
|
|
47
71
|
Gates 8 (Mock Detector) and 9 (Test Mutation Detector) run during the VERIFY phase and are enabled by default.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{c as L,j as e,r as m,v as _,Z as Q,m as X,h as ee,b as R,F as ge,U as z,X as te,L as se,w as je,M as fe,T as G,S as be,l as ae,k as ne,x as ve,E as Ee,Q as Ne,Y as re}from"./index-
|
|
1
|
+
import{c as L,j as e,r as m,v as _,Z as Q,m as X,h as ee,b as R,F as ge,U as z,X as te,L as se,w as je,M as fe,T as G,S as be,l as ae,k as ne,x as ve,E as Ee,Q as Ne,Y as re}from"./index-6Z4B0I6r.js";import{B as w}from"./Button-sp_FVGZj.js";import{T as ye}from"./trending-up-DmFIdVOc.js";import{C as I}from"./clock-DDScLol4.js";import{A as ke,U as ie}from"./Avatar-88MlpLO5.js";import{A as H}from"./activity-h1wU9a0L.js";import{R as le}from"./refresh-cw-B3dG1-Sb.js";import{G as Ae}from"./globe-Cby-g5Yb.js";import{C as we}from"./chevron-left-Bw4I1yGm.js";import{M as Ce}from"./mail-Dokiey5S.js";import{C as ce}from"./check-BWp8L5Cy.js";import{D as W}from"./dollar-sign-CydJu0kl.js";import{U as Se}from"./user-Dh00W8De.js";import{D as De}from"./database-CYZBHz51.js";import{L as Fe}from"./lock-BABtHe6K.js";import{H as Me}from"./hammer-BNScgGdp.js";import{S as Be}from"./shield-alert-CKJ1pzCz.js";import{S as $e}from"./server-CpN2GX4G.js";/**
|
|
2
2
|
* @license lucide-react v0.577.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as e}from"./index-
|
|
1
|
+
import{j as e}from"./index-6Z4B0I6r.js";import{C as r}from"./clock-DDScLol4.js";import{C as a}from"./circle-alert-C37PKXiC.js";import{C as l}from"./check-BWp8L5Cy.js";const i={completed:"bg-[#1FC5A8]/10 text-[#1FC5A8]",running:"bg-[#553DE9]/10 text-[#553DE9]",failed:"bg-[#C45B5B]/10 text-[#C45B5B]",started:"bg-[#D4A03C]/10 text-[#D4A03C]",empty:"bg-[#F8F4F0] text-[#6B6960]",version:"bg-[#553DE9]/10 text-[#553DE9]"};function o({status:t}){switch(t){case"completed":return e.jsx(l,{size:12});case"running":return e.jsxs("span",{className:"relative flex h-2 w-2",children:[e.jsx("span",{className:"animate-ping motion-reduce:animate-none absolute inline-flex h-full w-full rounded-full bg-current opacity-75"}),e.jsx("span",{className:"relative inline-flex rounded-full h-2 w-2 bg-current"})]});case"failed":return e.jsx(a,{size:12});case"started":return e.jsx(r,{size:12});default:return null}}function f({status:t,children:n,className:s=""}){return e.jsxs("span",{className:["inline-flex items-center gap-1 rounded-btn px-2.5 py-0.5 text-xs font-semibold",i[t],s].filter(Boolean).join(" "),children:[e.jsx(o,{status:t}),n]})}export{f as B};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as p,j as t}from"./index-
|
|
1
|
+
import{r as p,j as t}from"./index-6Z4B0I6r.js";const m={primary:"bg-[#553DE9] text-white hover:bg-[#4432c4] shadow-button rounded-btn",secondary:"border border-[#553DE9] text-[#553DE9] hover:bg-[#E8E4FD] bg-transparent rounded-btn",ghost:"text-[#36342E] hover:bg-[#F8F4F0] rounded-btn",danger:"bg-[#C45B5B]/10 text-[#C45B5B] border border-[#C45B5B]/20 hover:bg-[#C45B5B]/20 rounded-btn"},b={sm:"px-3 py-1.5 text-xs",md:"px-4 py-2 text-sm",lg:"px-6 py-3 text-base"},u={sm:14,md:16,lg:18};function h({size:e}){return t.jsxs("svg",{className:"animate-spin",width:e,height:e,viewBox:"0 0 24 24",fill:"none",children:[t.jsx("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),t.jsx("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"})]})}const B=p.forwardRef(({variant:e="primary",size:o="md",icon:n,iconRight:i,loading:r=!1,disabled:a,className:c="",children:l,...x},d)=>{const s=u[o];return t.jsxs("button",{ref:d,disabled:a||r,className:["inline-flex items-center justify-center gap-2 font-medium transition-colors",m[e],b[o],(a||r)&&"opacity-60 cursor-not-allowed",c].filter(Boolean).join(" "),...x,children:[r?t.jsx(h,{size:s}):n?t.jsx(n,{size:s}):null,l,i&&!r&&t.jsx(i,{size:s})]})});B.displayName="Button";export{B};
|