loki-mode 5.40.1 → 5.41.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/SKILL.md +5 -5
- package/VERSION +1 -1
- package/autonomy/loki +186 -4
- package/autonomy/run.sh +100 -4
- package/dashboard/__init__.py +1 -1
- package/dashboard/server.py +124 -0
- package/docs/INSTALLATION.md +1 -1
- package/mcp/__init__.py +1 -1
- package/package.json +1 -1
- package/skills/github-integration.md +43 -11
package/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: loki-mode
|
|
|
3
3
|
description: Multi-agent autonomous startup system. Triggers on "Loki Mode". Takes PRD to deployed product with zero human intervention. Requires --dangerously-skip-permissions flag.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Loki Mode v5.
|
|
6
|
+
# Loki Mode v5.41.0
|
|
7
7
|
|
|
8
8
|
**You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
|
|
9
9
|
|
|
@@ -127,8 +127,8 @@ GROWTH ──[continuous improvement loop]──> GROWTH
|
|
|
127
127
|
- Load only 1-2 skill modules at a time (from skills/00-index.md)
|
|
128
128
|
- Use Task tool with subagents for exploration (isolates context)
|
|
129
129
|
- IF context feels heavy: Create `.loki/signals/CONTEXT_CLEAR_REQUESTED`
|
|
130
|
-
- **Context Window Tracking (v5.40.
|
|
131
|
-
- **Notification Triggers (v5.40.
|
|
130
|
+
- **Context Window Tracking (v5.40.0):** Dashboard gauge, timeline, and per-agent breakdown at `GET /api/context`
|
|
131
|
+
- **Notification Triggers (v5.40.0):** Configurable alerts when context exceeds thresholds, tasks fail, or budget limits hit. Manage via `GET/PUT /api/notifications/triggers`
|
|
132
132
|
|
|
133
133
|
---
|
|
134
134
|
|
|
@@ -258,8 +258,8 @@ The following features are documented in skill modules but not yet fully automat
|
|
|
258
258
|
|---------|--------|-------|
|
|
259
259
|
| PRE-ACT goal drift detection | Planned | Agent-level attention check before each action; no automated enforcement yet |
|
|
260
260
|
| CONTINUITY.md working memory | Implemented (v5.35.0) | Auto-managed by run.sh, updated each iteration |
|
|
261
|
-
| GitHub
|
|
261
|
+
| GitHub integration | Implemented (v5.41.0) | Import, sync-back, PR creation, export. CLI: `loki github`, API: `/api/github/*` |
|
|
262
262
|
| Quality gates 3-reviewer system | Implemented (v5.35.0) | 5 specialist reviewers in `skills/quality-gates.md`; execution in run.sh |
|
|
263
263
|
| Benchmarks (HumanEval, SWE-bench) | Infrastructure only | Runner scripts and datasets exist in `benchmarks/`; no published results |
|
|
264
264
|
|
|
265
|
-
**v5.
|
|
265
|
+
**v5.41.0 | feat: GitHub sync-back, PR creation, export (fully wired) | ~260 lines core**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
5.
|
|
1
|
+
5.41.0
|
package/autonomy/loki
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
# loki status - Show current status
|
|
15
15
|
# loki dashboard - Open dashboard in browser
|
|
16
16
|
# loki import - Import GitHub issues
|
|
17
|
+
# loki github [cmd] - GitHub integration (sync|export|pr|status)
|
|
17
18
|
# loki help - Show this help
|
|
18
19
|
#===============================================================================
|
|
19
20
|
|
|
@@ -323,6 +324,7 @@ show_help() {
|
|
|
323
324
|
echo " notify [cmd] Send notifications (test|slack|discord|webhook|status)"
|
|
324
325
|
echo " voice [cmd] Voice input for PRD creation (status|listen|dictate|speak|start)"
|
|
325
326
|
echo " import Import GitHub issues as tasks"
|
|
327
|
+
echo " github [cmd] GitHub integration (sync|export|pr|status)"
|
|
326
328
|
echo " config [cmd] Manage configuration (show|init|edit|path)"
|
|
327
329
|
echo " completions [bash|zsh] Output shell completion scripts"
|
|
328
330
|
echo " memory [cmd] Cross-project learnings (list|show|search|stats)"
|
|
@@ -515,7 +517,7 @@ cmd_start() {
|
|
|
515
517
|
if [ -n "$prd_file" ]; then
|
|
516
518
|
args+=("$prd_file")
|
|
517
519
|
else
|
|
518
|
-
# No PRD file specified -- warn and confirm before
|
|
520
|
+
# No PRD file specified -- warn and confirm before starting
|
|
519
521
|
# Auto-confirm in CI environments or when LOKI_AUTO_CONFIRM is set
|
|
520
522
|
# LOKI_AUTO_CONFIRM takes precedence when explicitly set;
|
|
521
523
|
# fall back to CI env var only when LOKI_AUTO_CONFIRM is unset
|
|
@@ -524,10 +526,10 @@ cmd_start() {
|
|
|
524
526
|
echo -e "${YELLOW}Warning: No PRD file specified. Auto-confirming (CI mode).${NC}"
|
|
525
527
|
else
|
|
526
528
|
echo -e "${YELLOW}Warning: No PRD file specified.${NC}"
|
|
527
|
-
echo "Loki Mode will
|
|
528
|
-
echo "
|
|
529
|
+
echo "Loki Mode will analyze the existing codebase and generate"
|
|
530
|
+
echo "a PRD automatically. No requirements document needed."
|
|
529
531
|
echo ""
|
|
530
|
-
echo -e "
|
|
532
|
+
echo -e "Continue? [y/N] \c"
|
|
531
533
|
read -r confirm
|
|
532
534
|
if [[ ! "$confirm" =~ ^[Yy] ]]; then
|
|
533
535
|
echo "Aborted. Usage: loki start <path-to-prd.md>"
|
|
@@ -1832,6 +1834,183 @@ cmd_import() {
|
|
|
1832
1834
|
fi
|
|
1833
1835
|
}
|
|
1834
1836
|
|
|
1837
|
+
# GitHub integration management (v5.41.0)
|
|
1838
|
+
cmd_github() {
|
|
1839
|
+
local subcmd="${1:-help}"
|
|
1840
|
+
shift 2>/dev/null || true
|
|
1841
|
+
|
|
1842
|
+
case "$subcmd" in
|
|
1843
|
+
sync)
|
|
1844
|
+
# Sync completed tasks back to GitHub issues
|
|
1845
|
+
if [ ! -d "$LOKI_DIR" ]; then
|
|
1846
|
+
echo -e "${RED}No active Loki session found${NC}"
|
|
1847
|
+
exit 1
|
|
1848
|
+
fi
|
|
1849
|
+
|
|
1850
|
+
if ! command -v gh &>/dev/null; then
|
|
1851
|
+
echo -e "${RED}Error: gh CLI not found. Install with: brew install gh${NC}"
|
|
1852
|
+
exit 1
|
|
1853
|
+
fi
|
|
1854
|
+
|
|
1855
|
+
if ! gh auth status &>/dev/null; then
|
|
1856
|
+
echo -e "${RED}Error: gh CLI not authenticated. Run: gh auth login${NC}"
|
|
1857
|
+
exit 1
|
|
1858
|
+
fi
|
|
1859
|
+
|
|
1860
|
+
export LOKI_GITHUB_SYNC=true
|
|
1861
|
+
source "$RUN_SH" 2>/dev/null || true
|
|
1862
|
+
|
|
1863
|
+
echo -e "${GREEN}Syncing completed tasks to GitHub...${NC}"
|
|
1864
|
+
if type sync_github_completed_tasks &>/dev/null; then
|
|
1865
|
+
sync_github_completed_tasks
|
|
1866
|
+
echo -e "${GREEN}Sync complete.${NC}"
|
|
1867
|
+
|
|
1868
|
+
# Show what was synced
|
|
1869
|
+
if [ -f "$LOKI_DIR/github/synced.log" ]; then
|
|
1870
|
+
local count
|
|
1871
|
+
count=$(wc -l < "$LOKI_DIR/github/synced.log" | tr -d ' ')
|
|
1872
|
+
echo -e "${DIM}Total synced status updates: $count${NC}"
|
|
1873
|
+
fi
|
|
1874
|
+
else
|
|
1875
|
+
echo -e "${YELLOW}Sync function not available.${NC}"
|
|
1876
|
+
fi
|
|
1877
|
+
;;
|
|
1878
|
+
|
|
1879
|
+
export)
|
|
1880
|
+
# Export local tasks as GitHub issues
|
|
1881
|
+
if [ ! -d "$LOKI_DIR" ]; then
|
|
1882
|
+
echo -e "${RED}No active Loki session found${NC}"
|
|
1883
|
+
exit 1
|
|
1884
|
+
fi
|
|
1885
|
+
|
|
1886
|
+
if ! command -v gh &>/dev/null; then
|
|
1887
|
+
echo -e "${RED}Error: gh CLI not found. Install with: brew install gh${NC}"
|
|
1888
|
+
exit 1
|
|
1889
|
+
fi
|
|
1890
|
+
|
|
1891
|
+
echo -e "${GREEN}Exporting local tasks to GitHub issues...${NC}"
|
|
1892
|
+
source "$RUN_SH" 2>/dev/null || true
|
|
1893
|
+
if type export_tasks_to_github &>/dev/null; then
|
|
1894
|
+
export_tasks_to_github
|
|
1895
|
+
echo -e "${GREEN}Export complete.${NC}"
|
|
1896
|
+
else
|
|
1897
|
+
echo -e "${YELLOW}Export function not available.${NC}"
|
|
1898
|
+
fi
|
|
1899
|
+
;;
|
|
1900
|
+
|
|
1901
|
+
pr)
|
|
1902
|
+
# Create PR from completed work
|
|
1903
|
+
if ! command -v gh &>/dev/null; then
|
|
1904
|
+
echo -e "${RED}Error: gh CLI not found. Install with: brew install gh${NC}"
|
|
1905
|
+
exit 1
|
|
1906
|
+
fi
|
|
1907
|
+
|
|
1908
|
+
local feature_name="${1:-Loki Mode changes}"
|
|
1909
|
+
export LOKI_GITHUB_PR=true
|
|
1910
|
+
source "$RUN_SH" 2>/dev/null || true
|
|
1911
|
+
|
|
1912
|
+
echo -e "${GREEN}Creating pull request: $feature_name${NC}"
|
|
1913
|
+
if type create_github_pr &>/dev/null; then
|
|
1914
|
+
create_github_pr "$feature_name"
|
|
1915
|
+
else
|
|
1916
|
+
echo -e "${YELLOW}PR function not available.${NC}"
|
|
1917
|
+
fi
|
|
1918
|
+
;;
|
|
1919
|
+
|
|
1920
|
+
status)
|
|
1921
|
+
# Show GitHub integration status
|
|
1922
|
+
echo -e "${BOLD}GitHub Integration Status${NC}"
|
|
1923
|
+
echo ""
|
|
1924
|
+
|
|
1925
|
+
# gh CLI
|
|
1926
|
+
if command -v gh &>/dev/null; then
|
|
1927
|
+
echo -e " gh CLI: ${GREEN}installed$(gh --version 2>/dev/null | head -1 | sed 's/gh version /v/')${NC}"
|
|
1928
|
+
if gh auth status &>/dev/null 2>&1; then
|
|
1929
|
+
echo -e " Auth: ${GREEN}authenticated${NC}"
|
|
1930
|
+
else
|
|
1931
|
+
echo -e " Auth: ${RED}not authenticated${NC}"
|
|
1932
|
+
fi
|
|
1933
|
+
else
|
|
1934
|
+
echo -e " gh CLI: ${RED}not installed${NC}"
|
|
1935
|
+
fi
|
|
1936
|
+
|
|
1937
|
+
# Repo detection
|
|
1938
|
+
local repo=""
|
|
1939
|
+
repo=$(git remote get-url origin 2>/dev/null | sed 's|.*github.com[:/]||;s|\.git$||' || echo "")
|
|
1940
|
+
if [ -n "$repo" ]; then
|
|
1941
|
+
echo -e " Repository: ${GREEN}$repo${NC}"
|
|
1942
|
+
else
|
|
1943
|
+
echo -e " Repository: ${YELLOW}not detected${NC}"
|
|
1944
|
+
fi
|
|
1945
|
+
|
|
1946
|
+
# Config flags
|
|
1947
|
+
echo ""
|
|
1948
|
+
echo -e "${BOLD}Configuration${NC}"
|
|
1949
|
+
echo -e " LOKI_GITHUB_IMPORT: ${LOKI_GITHUB_IMPORT:-false}"
|
|
1950
|
+
echo -e " LOKI_GITHUB_SYNC: ${LOKI_GITHUB_SYNC:-false}"
|
|
1951
|
+
echo -e " LOKI_GITHUB_PR: ${LOKI_GITHUB_PR:-false}"
|
|
1952
|
+
echo -e " LOKI_GITHUB_LABELS: ${LOKI_GITHUB_LABELS:-(all)}"
|
|
1953
|
+
echo -e " LOKI_GITHUB_LIMIT: ${LOKI_GITHUB_LIMIT:-100}"
|
|
1954
|
+
|
|
1955
|
+
# Sync log
|
|
1956
|
+
if [ -f "$LOKI_DIR/github/synced.log" ]; then
|
|
1957
|
+
echo ""
|
|
1958
|
+
echo -e "${BOLD}Sync History${NC}"
|
|
1959
|
+
local total
|
|
1960
|
+
total=$(wc -l < "$LOKI_DIR/github/synced.log" | tr -d ' ')
|
|
1961
|
+
echo -e " Total synced updates: $total"
|
|
1962
|
+
echo -e " Recent:"
|
|
1963
|
+
tail -5 "$LOKI_DIR/github/synced.log" | sed 's/^/ /'
|
|
1964
|
+
fi
|
|
1965
|
+
|
|
1966
|
+
# Imported tasks
|
|
1967
|
+
if [ -f "$LOKI_DIR/queue/pending.json" ]; then
|
|
1968
|
+
local gh_tasks
|
|
1969
|
+
gh_tasks=$(python3 -c "
|
|
1970
|
+
import json
|
|
1971
|
+
try:
|
|
1972
|
+
with open('$LOKI_DIR/queue/pending.json') as f:
|
|
1973
|
+
data = json.load(f)
|
|
1974
|
+
tasks = data.get('tasks', data) if isinstance(data, dict) else data
|
|
1975
|
+
gh = [t for t in tasks if t.get('source') == 'github']
|
|
1976
|
+
print(len(gh))
|
|
1977
|
+
except: print(0)
|
|
1978
|
+
" 2>/dev/null || echo "0")
|
|
1979
|
+
echo ""
|
|
1980
|
+
echo -e "${BOLD}Imported Issues${NC}"
|
|
1981
|
+
echo -e " GitHub tasks in queue: $gh_tasks"
|
|
1982
|
+
fi
|
|
1983
|
+
;;
|
|
1984
|
+
|
|
1985
|
+
help|*)
|
|
1986
|
+
echo -e "${BOLD}loki github${NC} - GitHub integration management"
|
|
1987
|
+
echo ""
|
|
1988
|
+
echo "Commands:"
|
|
1989
|
+
echo " status Show GitHub integration status"
|
|
1990
|
+
echo " sync Sync completed task status back to GitHub issues"
|
|
1991
|
+
echo " export Export local tasks as new GitHub issues"
|
|
1992
|
+
echo " pr [name] Create pull request from completed work"
|
|
1993
|
+
echo ""
|
|
1994
|
+
echo "Environment Variables:"
|
|
1995
|
+
echo " LOKI_GITHUB_IMPORT=true Import open issues as tasks on start"
|
|
1996
|
+
echo " LOKI_GITHUB_SYNC=true Sync status back to issues during session"
|
|
1997
|
+
echo " LOKI_GITHUB_PR=true Create PR when session completes successfully"
|
|
1998
|
+
echo " LOKI_GITHUB_LABELS=bug Filter issues by label (comma-separated)"
|
|
1999
|
+
echo " LOKI_GITHUB_MILESTONE=v2 Filter by milestone"
|
|
2000
|
+
echo " LOKI_GITHUB_ASSIGNEE=me Filter by assignee"
|
|
2001
|
+
echo " LOKI_GITHUB_LIMIT=50 Max issues to import (default: 100)"
|
|
2002
|
+
echo " LOKI_GITHUB_PR_LABEL=loki Label to add to created PRs"
|
|
2003
|
+
echo ""
|
|
2004
|
+
echo "Examples:"
|
|
2005
|
+
echo " loki github status"
|
|
2006
|
+
echo " loki github sync"
|
|
2007
|
+
echo " loki github export"
|
|
2008
|
+
echo " loki github pr \"Add user authentication\""
|
|
2009
|
+
echo " LOKI_GITHUB_SYNC=true loki start --github ./prd.md"
|
|
2010
|
+
;;
|
|
2011
|
+
esac
|
|
2012
|
+
}
|
|
2013
|
+
|
|
1835
2014
|
# Parse GitHub issue using issue-parser.sh
|
|
1836
2015
|
cmd_issue_parse() {
|
|
1837
2016
|
local issue_ref=""
|
|
@@ -4278,6 +4457,9 @@ main() {
|
|
|
4278
4457
|
import)
|
|
4279
4458
|
cmd_import
|
|
4280
4459
|
;;
|
|
4460
|
+
github)
|
|
4461
|
+
cmd_github "$@"
|
|
4462
|
+
;;
|
|
4281
4463
|
issue)
|
|
4282
4464
|
cmd_issue "$@"
|
|
4283
4465
|
;;
|
package/autonomy/run.sh
CHANGED
|
@@ -1273,10 +1273,12 @@ create_github_pr() {
|
|
|
1273
1273
|
local pr_body=".loki/reports/pr-body.md"
|
|
1274
1274
|
mkdir -p "$(dirname "$pr_body")"
|
|
1275
1275
|
|
|
1276
|
+
local version
|
|
1277
|
+
version=$(cat "${SCRIPT_DIR%/*}/VERSION" 2>/dev/null || echo "unknown")
|
|
1276
1278
|
cat > "$pr_body" << EOF
|
|
1277
1279
|
## Summary
|
|
1278
1280
|
|
|
1279
|
-
Automated implementation by Loki Mode
|
|
1281
|
+
Automated implementation by Loki Mode v$version ($ITERATION_COUNT iterations, provider: ${PROVIDER_NAME:-claude})
|
|
1280
1282
|
|
|
1281
1283
|
### Feature: $feature_name
|
|
1282
1284
|
|
|
@@ -1349,24 +1351,105 @@ sync_github_status() {
|
|
|
1349
1351
|
return 1
|
|
1350
1352
|
fi
|
|
1351
1353
|
|
|
1354
|
+
# Track synced issues to avoid duplicate comments
|
|
1355
|
+
mkdir -p .loki/github
|
|
1356
|
+
local sync_log=".loki/github/synced.log"
|
|
1357
|
+
local sync_key="${issue_number}:${status}"
|
|
1358
|
+
if [ -f "$sync_log" ] && grep -qF "$sync_key" "$sync_log" 2>/dev/null; then
|
|
1359
|
+
return 0 # Already synced this status
|
|
1360
|
+
fi
|
|
1361
|
+
|
|
1352
1362
|
case "$status" in
|
|
1353
1363
|
"in_progress")
|
|
1354
1364
|
gh issue comment "$issue_number" --repo "$repo" \
|
|
1355
|
-
--body "Loki Mode
|
|
1365
|
+
--body "**Loki Mode** -- Working on this issue (iteration $ITERATION_COUNT)" \
|
|
1356
1366
|
2>/dev/null || true
|
|
1357
1367
|
;;
|
|
1358
1368
|
"completed")
|
|
1369
|
+
local branch
|
|
1370
|
+
branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "main")
|
|
1371
|
+
local commit
|
|
1372
|
+
commit=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown")
|
|
1359
1373
|
gh issue comment "$issue_number" --repo "$repo" \
|
|
1360
|
-
--body "Loki Mode
|
|
1374
|
+
--body "**Loki Mode** -- Implementation complete on \`$branch\` ($commit). ${message:-}" \
|
|
1361
1375
|
2>/dev/null || true
|
|
1362
1376
|
;;
|
|
1363
1377
|
"closed")
|
|
1364
1378
|
gh issue close "$issue_number" --repo "$repo" \
|
|
1365
1379
|
--reason "completed" \
|
|
1366
|
-
--comment "Loki Mode
|
|
1380
|
+
--comment "**Loki Mode** -- Resolved. ${message:-}" \
|
|
1367
1381
|
2>/dev/null || true
|
|
1368
1382
|
;;
|
|
1369
1383
|
esac
|
|
1384
|
+
|
|
1385
|
+
# Record sync to avoid duplicates
|
|
1386
|
+
echo "$sync_key" >> "$sync_log"
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
# Sync all completed GitHub-sourced tasks back to their issues
|
|
1390
|
+
# Called after each iteration and at session end
|
|
1391
|
+
sync_github_completed_tasks() {
|
|
1392
|
+
if [ "$GITHUB_SYNC" != "true" ]; then
|
|
1393
|
+
return 0
|
|
1394
|
+
fi
|
|
1395
|
+
|
|
1396
|
+
if ! check_github_cli; then
|
|
1397
|
+
return 0
|
|
1398
|
+
fi
|
|
1399
|
+
|
|
1400
|
+
local completed_file=".loki/queue/completed.json"
|
|
1401
|
+
if [ ! -f "$completed_file" ]; then
|
|
1402
|
+
return 0
|
|
1403
|
+
fi
|
|
1404
|
+
|
|
1405
|
+
# Find GitHub-sourced tasks in completed queue that haven't been synced
|
|
1406
|
+
python3 -c "
|
|
1407
|
+
import json, sys
|
|
1408
|
+
try:
|
|
1409
|
+
with open('$completed_file') as f:
|
|
1410
|
+
tasks = json.load(f)
|
|
1411
|
+
for t in tasks:
|
|
1412
|
+
tid = t.get('id', '')
|
|
1413
|
+
if tid.startswith('github-'):
|
|
1414
|
+
print(tid)
|
|
1415
|
+
except Exception:
|
|
1416
|
+
pass
|
|
1417
|
+
" 2>/dev/null | while read -r task_id; do
|
|
1418
|
+
sync_github_status "$task_id" "completed"
|
|
1419
|
+
done
|
|
1420
|
+
}
|
|
1421
|
+
|
|
1422
|
+
# Sync GitHub-sourced tasks currently in-progress
|
|
1423
|
+
sync_github_in_progress_tasks() {
|
|
1424
|
+
if [ "$GITHUB_SYNC" != "true" ]; then
|
|
1425
|
+
return 0
|
|
1426
|
+
fi
|
|
1427
|
+
|
|
1428
|
+
if ! check_github_cli; then
|
|
1429
|
+
return 0
|
|
1430
|
+
fi
|
|
1431
|
+
|
|
1432
|
+
local pending_file=".loki/queue/pending.json"
|
|
1433
|
+
if [ ! -f "$pending_file" ]; then
|
|
1434
|
+
return 0
|
|
1435
|
+
fi
|
|
1436
|
+
|
|
1437
|
+
# Find GitHub-sourced tasks in pending queue (about to be worked on)
|
|
1438
|
+
python3 -c "
|
|
1439
|
+
import json
|
|
1440
|
+
try:
|
|
1441
|
+
with open('$pending_file') as f:
|
|
1442
|
+
data = json.load(f)
|
|
1443
|
+
tasks = data.get('tasks', data) if isinstance(data, dict) else data
|
|
1444
|
+
for t in tasks:
|
|
1445
|
+
tid = t.get('id', '')
|
|
1446
|
+
if tid.startswith('github-'):
|
|
1447
|
+
print(tid)
|
|
1448
|
+
except Exception:
|
|
1449
|
+
pass
|
|
1450
|
+
" 2>/dev/null | while read -r task_id; do
|
|
1451
|
+
sync_github_status "$task_id" "in_progress"
|
|
1452
|
+
done
|
|
1370
1453
|
}
|
|
1371
1454
|
|
|
1372
1455
|
# Export tasks to GitHub issues (reverse sync)
|
|
@@ -2804,6 +2887,9 @@ EFF_EOF
|
|
|
2804
2887
|
# Check notification triggers (v5.40.0)
|
|
2805
2888
|
check_notification_triggers "$iteration"
|
|
2806
2889
|
|
|
2890
|
+
# Sync completed GitHub tasks back to issues (v5.41.0)
|
|
2891
|
+
sync_github_completed_tasks
|
|
2892
|
+
|
|
2807
2893
|
# Get task from in-progress
|
|
2808
2894
|
local in_progress_file=".loki/queue/in-progress.json"
|
|
2809
2895
|
local completed_file=".loki/queue/completed.json"
|
|
@@ -7020,6 +7106,8 @@ main() {
|
|
|
7020
7106
|
# Import GitHub issues if enabled (v4.1.0)
|
|
7021
7107
|
if [ "$GITHUB_IMPORT" = "true" ]; then
|
|
7022
7108
|
import_github_issues
|
|
7109
|
+
# Notify GitHub that imported issues are being worked on (v5.41.0)
|
|
7110
|
+
sync_github_in_progress_tasks
|
|
7023
7111
|
fi
|
|
7024
7112
|
|
|
7025
7113
|
# Start web dashboard (if enabled)
|
|
@@ -7109,6 +7197,14 @@ main() {
|
|
|
7109
7197
|
run_autonomous "$PRD_PATH" || result=$?
|
|
7110
7198
|
fi
|
|
7111
7199
|
|
|
7200
|
+
# Final GitHub sync: sync all completed tasks and create PR (v5.41.0)
|
|
7201
|
+
sync_github_completed_tasks
|
|
7202
|
+
if [ "$GITHUB_PR" = "true" ] && [ "$result" = "0" ]; then
|
|
7203
|
+
local feature_name="${PRD_PATH:-Codebase improvements}"
|
|
7204
|
+
feature_name=$(basename "$feature_name" .md 2>/dev/null || echo "$feature_name")
|
|
7205
|
+
create_github_pr "$feature_name"
|
|
7206
|
+
fi
|
|
7207
|
+
|
|
7112
7208
|
# Extract and save learnings from this session
|
|
7113
7209
|
extract_learnings_from_session
|
|
7114
7210
|
|
package/dashboard/__init__.py
CHANGED
package/dashboard/server.py
CHANGED
|
@@ -2789,6 +2789,130 @@ async def get_secrets_status():
|
|
|
2789
2789
|
}
|
|
2790
2790
|
|
|
2791
2791
|
|
|
2792
|
+
# =============================================================================
|
|
2793
|
+
# GitHub Integration API (v5.41.0)
|
|
2794
|
+
# =============================================================================
|
|
2795
|
+
|
|
2796
|
+
|
|
2797
|
+
@app.get("/api/github/status")
|
|
2798
|
+
async def get_github_status(token: Optional[dict] = Depends(auth.get_current_token)):
|
|
2799
|
+
"""Get GitHub integration status and configuration."""
|
|
2800
|
+
loki_dir = _get_loki_dir()
|
|
2801
|
+
result: dict[str, Any] = {
|
|
2802
|
+
"import_enabled": os.environ.get("LOKI_GITHUB_IMPORT", "false") == "true",
|
|
2803
|
+
"sync_enabled": os.environ.get("LOKI_GITHUB_SYNC", "false") == "true",
|
|
2804
|
+
"pr_enabled": os.environ.get("LOKI_GITHUB_PR", "false") == "true",
|
|
2805
|
+
"labels_filter": os.environ.get("LOKI_GITHUB_LABELS", ""),
|
|
2806
|
+
"milestone_filter": os.environ.get("LOKI_GITHUB_MILESTONE", ""),
|
|
2807
|
+
"limit": int(os.environ.get("LOKI_GITHUB_LIMIT", "100")),
|
|
2808
|
+
"imported_tasks": 0,
|
|
2809
|
+
"synced_updates": 0,
|
|
2810
|
+
"repo": None,
|
|
2811
|
+
}
|
|
2812
|
+
|
|
2813
|
+
# Count imported GitHub tasks from pending queue
|
|
2814
|
+
pending_file = loki_dir / "queue" / "pending.json"
|
|
2815
|
+
if pending_file.exists():
|
|
2816
|
+
try:
|
|
2817
|
+
data = json.loads(pending_file.read_text())
|
|
2818
|
+
tasks = data.get("tasks", data) if isinstance(data, dict) else data
|
|
2819
|
+
result["imported_tasks"] = sum(1 for t in tasks if t.get("source") == "github")
|
|
2820
|
+
except Exception:
|
|
2821
|
+
pass
|
|
2822
|
+
|
|
2823
|
+
# Count sync log entries
|
|
2824
|
+
sync_log = loki_dir / "github" / "synced.log"
|
|
2825
|
+
if sync_log.exists():
|
|
2826
|
+
try:
|
|
2827
|
+
result["synced_updates"] = sum(1 for _ in sync_log.open())
|
|
2828
|
+
except Exception:
|
|
2829
|
+
pass
|
|
2830
|
+
|
|
2831
|
+
# Detect repo from git
|
|
2832
|
+
try:
|
|
2833
|
+
import subprocess
|
|
2834
|
+
url = subprocess.run(
|
|
2835
|
+
["git", "remote", "get-url", "origin"],
|
|
2836
|
+
capture_output=True, text=True, timeout=5,
|
|
2837
|
+
cwd=str(loki_dir.parent) if loki_dir.name == ".loki" else None
|
|
2838
|
+
)
|
|
2839
|
+
if url.returncode == 0:
|
|
2840
|
+
repo = url.stdout.strip()
|
|
2841
|
+
# Parse owner/repo from URL
|
|
2842
|
+
for prefix in ["https://github.com/", "git@github.com:"]:
|
|
2843
|
+
if repo.startswith(prefix):
|
|
2844
|
+
repo = repo[len(prefix):]
|
|
2845
|
+
break
|
|
2846
|
+
result["repo"] = repo.removesuffix(".git")
|
|
2847
|
+
except Exception:
|
|
2848
|
+
pass
|
|
2849
|
+
|
|
2850
|
+
return result
|
|
2851
|
+
|
|
2852
|
+
|
|
2853
|
+
@app.get("/api/github/tasks")
|
|
2854
|
+
async def get_github_tasks(token: Optional[dict] = Depends(auth.get_current_token)):
|
|
2855
|
+
"""Get all GitHub-sourced tasks and their sync status."""
|
|
2856
|
+
loki_dir = _get_loki_dir()
|
|
2857
|
+
tasks: list[dict] = []
|
|
2858
|
+
|
|
2859
|
+
# Collect GitHub tasks from all queues
|
|
2860
|
+
for queue_name in ["pending", "in-progress", "completed", "failed"]:
|
|
2861
|
+
queue_file = loki_dir / "queue" / f"{queue_name}.json"
|
|
2862
|
+
if queue_file.exists():
|
|
2863
|
+
try:
|
|
2864
|
+
data = json.loads(queue_file.read_text())
|
|
2865
|
+
items = data.get("tasks", data) if isinstance(data, dict) else data
|
|
2866
|
+
for t in items:
|
|
2867
|
+
if t.get("source") == "github" or str(t.get("id", "")).startswith("github-"):
|
|
2868
|
+
t["queue"] = queue_name
|
|
2869
|
+
tasks.append(t)
|
|
2870
|
+
except Exception:
|
|
2871
|
+
pass
|
|
2872
|
+
|
|
2873
|
+
# Load sync log to annotate sync status
|
|
2874
|
+
synced: set[str] = set()
|
|
2875
|
+
sync_log = loki_dir / "github" / "synced.log"
|
|
2876
|
+
if sync_log.exists():
|
|
2877
|
+
try:
|
|
2878
|
+
synced = set(sync_log.read_text().strip().splitlines())
|
|
2879
|
+
except Exception:
|
|
2880
|
+
pass
|
|
2881
|
+
|
|
2882
|
+
for t in tasks:
|
|
2883
|
+
issue_num = str(t.get("github_issue", ""))
|
|
2884
|
+
if not issue_num:
|
|
2885
|
+
issue_num = str(t.get("id", "")).replace("github-", "")
|
|
2886
|
+
t["synced_statuses"] = [
|
|
2887
|
+
s.split(":")[1] for s in synced if s.startswith(f"{issue_num}:")
|
|
2888
|
+
]
|
|
2889
|
+
|
|
2890
|
+
return {"tasks": tasks, "total": len(tasks)}
|
|
2891
|
+
|
|
2892
|
+
|
|
2893
|
+
@app.get("/api/github/sync-log")
|
|
2894
|
+
async def get_github_sync_log(
|
|
2895
|
+
limit: int = Query(default=50, ge=1, le=500),
|
|
2896
|
+
token: Optional[dict] = Depends(auth.get_current_token)
|
|
2897
|
+
):
|
|
2898
|
+
"""Get the GitHub sync log (status updates sent to issues)."""
|
|
2899
|
+
loki_dir = _get_loki_dir()
|
|
2900
|
+
sync_log = loki_dir / "github" / "synced.log"
|
|
2901
|
+
entries: list[dict] = []
|
|
2902
|
+
|
|
2903
|
+
if sync_log.exists():
|
|
2904
|
+
try:
|
|
2905
|
+
lines = sync_log.read_text().strip().splitlines()
|
|
2906
|
+
for line in lines[-limit:]:
|
|
2907
|
+
parts = line.split(":", 1)
|
|
2908
|
+
if len(parts) == 2:
|
|
2909
|
+
entries.append({"issue": parts[0], "status": parts[1]})
|
|
2910
|
+
except Exception:
|
|
2911
|
+
pass
|
|
2912
|
+
|
|
2913
|
+
return {"entries": entries, "total": len(entries)}
|
|
2914
|
+
|
|
2915
|
+
|
|
2792
2916
|
# =============================================================================
|
|
2793
2917
|
# Process Health / Watchdog API
|
|
2794
2918
|
# =============================================================================
|
package/docs/INSTALLATION.md
CHANGED
package/mcp/__init__.py
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# GitHub Integration (v5.
|
|
1
|
+
# GitHub Integration (v5.41.0)
|
|
2
2
|
|
|
3
|
-
**When:** Importing issues from GitHub, creating PRs, syncing task status
|
|
3
|
+
**When:** Importing issues from GitHub, creating PRs, syncing task status back
|
|
4
4
|
|
|
5
5
|
> **Requires:** `gh` CLI authenticated (`gh auth status`)
|
|
6
6
|
|
|
@@ -10,9 +10,13 @@
|
|
|
10
10
|
|
|
11
11
|
| Action | Command | Result |
|
|
12
12
|
|--------|---------|--------|
|
|
13
|
-
| Import issues as tasks | `LOKI_GITHUB_IMPORT=true` | Fetches open issues, creates pending tasks |
|
|
13
|
+
| Import issues as tasks | `loki start --github` or `LOKI_GITHUB_IMPORT=true` | Fetches open issues, creates pending tasks |
|
|
14
14
|
| Create PR on completion | `LOKI_GITHUB_PR=true` | Auto-creates PR with task summaries |
|
|
15
|
-
| Sync status back | `LOKI_GITHUB_SYNC=true` | Comments progress on source issues |
|
|
15
|
+
| Sync status back | `LOKI_GITHUB_SYNC=true` | Comments progress on source issues (deduplicated) |
|
|
16
|
+
| Manual sync | `loki github sync` | Sync completed tasks to GitHub now |
|
|
17
|
+
| Export tasks | `loki github export` | Create GitHub issues from local tasks |
|
|
18
|
+
| Manual PR | `loki github pr "feature name"` | Create PR from current work |
|
|
19
|
+
| Check status | `loki github status` | Show config, sync history, imported count |
|
|
16
20
|
| Import from URL | `LOKI_GITHUB_REPO=owner/repo` | Specify repo if not auto-detected |
|
|
17
21
|
|
|
18
22
|
---
|
|
@@ -167,13 +171,41 @@ LOKI_GITHUB_IMPORT=true \
|
|
|
167
171
|
|
|
168
172
|
---
|
|
169
173
|
|
|
170
|
-
##
|
|
174
|
+
## CLI Commands
|
|
171
175
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
176
|
+
```bash
|
|
177
|
+
# Check GitHub integration status
|
|
178
|
+
loki github status
|
|
179
|
+
|
|
180
|
+
# Sync completed task statuses back to GitHub issues
|
|
181
|
+
loki github sync
|
|
182
|
+
|
|
183
|
+
# Export local tasks as new GitHub issues
|
|
184
|
+
loki github export
|
|
185
|
+
|
|
186
|
+
# Create PR from completed work
|
|
187
|
+
loki github pr "Add user authentication"
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## Dashboard API
|
|
193
|
+
|
|
194
|
+
| Endpoint | Method | Description |
|
|
195
|
+
|----------|--------|-------------|
|
|
196
|
+
| `/api/github/status` | GET | Integration config, repo, sync count |
|
|
197
|
+
| `/api/github/tasks` | GET | All GitHub-sourced tasks with sync status |
|
|
198
|
+
| `/api/github/sync-log` | GET | History of status updates sent to issues |
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## Sync Behavior
|
|
203
|
+
|
|
204
|
+
- **On session start** (`LOKI_GITHUB_IMPORT=true`): Imports issues, posts "in_progress" comment
|
|
205
|
+
- **After each iteration** (`LOKI_GITHUB_SYNC=true`): Syncs completed GitHub tasks
|
|
206
|
+
- **On session end** (`LOKI_GITHUB_PR=true`): Final sync + creates PR with `Closes #N` references
|
|
207
|
+
- **Deduplication**: Sync log at `.loki/github/synced.log` prevents duplicate comments
|
|
208
|
+
- **Manual**: `loki github sync` can be run anytime outside a session
|
|
177
209
|
|
|
178
210
|
---
|
|
179
211
|
|
|
@@ -215,4 +247,4 @@ gh repo set-default owner/repo
|
|
|
215
247
|
|
|
216
248
|
---
|
|
217
249
|
|
|
218
|
-
**v5.
|
|
250
|
+
**v5.41.0 | GitHub Integration (full sync-back) | ~250 lines**
|