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 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.40.1
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.1):** Dashboard gauge, timeline, and per-agent breakdown at `GET /api/context`
131
- - **Notification Triggers (v5.40.1):** Configurable alerts when context exceeds thresholds, tasks fail, or budget limits hit. Manage via `GET/PUT /api/notifications/triggers`
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 issue import | Planned | Config flags exist (`LOKI_GITHUB_IMPORT`); `gh` CLI integration partial |
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.40.1 | fix: 46-bug audit across all distributions, JSON injection, Docker mounts, auth hardening | ~260 lines core**
265
+ **v5.41.0 | feat: GitHub sync-back, PR creation, export (fully wired) | ~260 lines core**
package/VERSION CHANGED
@@ -1 +1 @@
1
- 5.40.1
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 consuming API credits
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 start autonomous execution in the current directory"
528
- echo "without a requirements document."
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 "This will consume API credits. Continue? [y/N] \c"
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 v4.1.0
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: Task in progress - ${message:-implementing solution...}" \
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: Implementation complete. ${message:-}" \
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: Fixed. ${message:-}" \
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
 
@@ -7,7 +7,7 @@ Modules:
7
7
  control: Session control API (start/stop/pause/resume)
8
8
  """
9
9
 
10
- __version__ = "5.40.1"
10
+ __version__ = "5.41.0"
11
11
 
12
12
  # Expose the control app for easy import
13
13
  try:
@@ -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
  # =============================================================================
@@ -2,7 +2,7 @@
2
2
 
3
3
  Complete installation instructions for all platforms and use cases.
4
4
 
5
- **Version:** v5.40.1
5
+ **Version:** v5.41.0
6
6
 
7
7
  ---
8
8
 
package/mcp/__init__.py CHANGED
@@ -21,4 +21,4 @@ try:
21
21
  except ImportError:
22
22
  __all__ = ['mcp']
23
23
 
24
- __version__ = '5.40.1'
24
+ __version__ = '5.41.0'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loki-mode",
3
- "version": "5.40.1",
3
+ "version": "5.41.0",
4
4
  "description": "Multi-agent autonomous startup system for Claude Code, Codex CLI, and Gemini CLI",
5
5
  "keywords": [
6
6
  "claude",
@@ -1,6 +1,6 @@
1
- # GitHub Integration (v5.25.0)
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
- ## Integration with Dashboard
174
+ ## CLI Commands
171
175
 
172
- The dashboard shows GitHub-sourced tasks with:
173
- - GitHub icon badge
174
- - Direct link to issue
175
- - Sync status indicator
176
- - "Import from GitHub" button (calls `gh issue list`)
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.25.0 | GitHub Integration | ~100 lines**
250
+ **v5.41.0 | GitHub Integration (full sync-back) | ~250 lines**