loki-mode 5.30.0 → 5.32.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/autonomy/run.sh CHANGED
@@ -712,15 +712,28 @@ emit_learning_signal() {
712
712
 
713
713
  # Track iteration timing for efficiency signals
714
714
  ITERATION_START_MS=""
715
+
716
+ # Get current time in milliseconds (portable: works on macOS BSD date and GNU date)
717
+ _now_ms() {
718
+ local ms
719
+ ms=$(date +%s%3N 2>/dev/null)
720
+ # macOS BSD date doesn't support %N -- outputs literal "N" or "%3N"
721
+ # Detect non-numeric output and fall back to seconds * 1000
722
+ case "$ms" in
723
+ *[!0-9]*) echo $(( $(date +%s) * 1000 )) ;;
724
+ *) echo "$ms" ;;
725
+ esac
726
+ }
727
+
715
728
  record_iteration_start() {
716
- ITERATION_START_MS=$(date +%s%3N 2>/dev/null || echo $(($(date +%s) * 1000)))
729
+ ITERATION_START_MS=$(_now_ms)
717
730
  }
718
731
 
719
732
  # Get iteration duration in milliseconds
720
733
  get_iteration_duration_ms() {
721
734
  if [ -n "$ITERATION_START_MS" ]; then
722
735
  local end_ms
723
- end_ms=$(date +%s%3N 2>/dev/null || echo $(($(date +%s) * 1000)))
736
+ end_ms=$(_now_ms)
724
737
  echo $((end_ms - ITERATION_START_MS))
725
738
  else
726
739
  echo "0"
@@ -2577,7 +2590,7 @@ track_iteration_complete() {
2577
2590
  elif [ "${PROVIDER_NAME:-claude}" = "gemini" ]; then
2578
2591
  model_tier="gemini-3-pro"
2579
2592
  fi
2580
- local phase="$current_phase"
2593
+ local phase="${LAST_KNOWN_PHASE:-}"
2581
2594
  [ -z "$phase" ] && phase=$(python3 -c "import json; print(json.load(open('.loki/state/orchestrator.json')).get('currentPhase', 'unknown'))" 2>/dev/null || echo "unknown")
2582
2595
  cat > ".loki/metrics/efficiency/iteration-${iteration}.json" << EFF_EOF
2583
2596
  {
@@ -7,7 +7,7 @@ Modules:
7
7
  control: Session control API (start/stop/pause/resume)
8
8
  """
9
9
 
10
- __version__ = "5.30.0"
10
+ __version__ = "5.32.0"
11
11
 
12
12
  # Expose the control app for easy import
13
13
  try:
@@ -2200,7 +2200,7 @@ except ImportError as e:
2200
2200
  # =============================================================================
2201
2201
  # Must be configured AFTER all API routes to avoid conflicts
2202
2202
 
2203
- from fastapi.responses import FileResponse, HTMLResponse
2203
+ from fastapi.responses import FileResponse, HTMLResponse, Response
2204
2204
 
2205
2205
  # Find static files in multiple possible locations
2206
2206
  DASHBOARD_DIR = os.path.dirname(os.path.abspath(__file__))
@@ -2240,6 +2240,17 @@ if STATIC_DIR:
2240
2240
  if os.path.isdir(ASSETS_DIR):
2241
2241
  app.mount("/assets", StaticFiles(directory=ASSETS_DIR), name="assets")
2242
2242
 
2243
+ # Serve favicon.svg from static directory
2244
+ @app.get("/favicon.svg", include_in_schema=False)
2245
+ async def serve_favicon():
2246
+ """Serve the dashboard favicon."""
2247
+ if STATIC_DIR:
2248
+ favicon_path = os.path.join(STATIC_DIR, "favicon.svg")
2249
+ if os.path.isfile(favicon_path):
2250
+ return FileResponse(favicon_path, media_type="image/svg+xml")
2251
+ return Response(status_code=404)
2252
+
2253
+
2243
2254
  # Serve index.html or standalone HTML for root
2244
2255
  @app.get("/", include_in_schema=False)
2245
2256
  async def serve_index():
@@ -0,0 +1,5 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" width="32" height="32">
2
+ <path d="M16 6C8 6 2 16 2 16s6 10 14 10 14-10 14-10S24 6 16 6z" fill="none" stroke="#7c3aed" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
3
+ <circle cx="16" cy="16" r="5" fill="#7c3aed"/>
4
+ <circle cx="16" cy="16" r="2" fill="#fff"/>
5
+ </svg>
@@ -6,7 +6,7 @@
6
6
  <meta name="description" content="Loki Mode Dashboard - Self-contained autonomous AI system monitor">
7
7
  <meta name="theme-color" content="#8b5cf6">
8
8
  <title>Loki Mode Dashboard</title>
9
- <link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><rect fill='%238b5cf6' rx='15' width='100' height='100'/><text x='50' y='72' font-size='60' font-weight='bold' text-anchor='middle' fill='white'>L</text></svg>">
9
+ <link rel="icon" type="image/svg+xml" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32' width='32' height='32'><path d='M16 6C8 6 2 16 2 16s6 10 14 10 14-10 14-10S24 6 16 6z' fill='none' stroke='%237c3aed' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/><circle cx='16' cy='16' r='5' fill='%237c3aed'/><circle cx='16' cy='16' r='2' fill='%23fff'/></svg>">
10
10
  <style>
11
11
  /* CSS Reset and Base Styles */
12
12
  :root {
@@ -351,6 +351,105 @@
351
351
  ::-webkit-scrollbar-track { background: transparent; }
352
352
  ::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.1); border-radius: 3px; }
353
353
  ::-webkit-scrollbar-thumb:hover { background: rgba(0,0,0,0.2); }
354
+
355
+ /* Keyboard Shortcuts Help Overlay */
356
+ .shortcuts-overlay {
357
+ display: none;
358
+ position: fixed;
359
+ inset: 0;
360
+ background: rgba(0, 0, 0, 0.6);
361
+ z-index: 1000;
362
+ align-items: center;
363
+ justify-content: center;
364
+ }
365
+
366
+ .shortcuts-overlay.visible {
367
+ display: flex;
368
+ }
369
+
370
+ .shortcuts-dialog {
371
+ background: var(--loki-bg-card);
372
+ border: 1px solid var(--loki-border);
373
+ border-radius: 12px;
374
+ padding: 24px;
375
+ max-width: 480px;
376
+ width: 90%;
377
+ max-height: 80vh;
378
+ overflow-y: auto;
379
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
380
+ }
381
+
382
+ .shortcuts-header {
383
+ display: flex;
384
+ justify-content: space-between;
385
+ align-items: center;
386
+ margin-bottom: 16px;
387
+ padding-bottom: 12px;
388
+ border-bottom: 1px solid var(--loki-border);
389
+ }
390
+
391
+ .shortcuts-title {
392
+ font-size: 16px;
393
+ font-weight: 600;
394
+ color: var(--loki-text-primary);
395
+ }
396
+
397
+ .shortcuts-close {
398
+ background: none;
399
+ border: none;
400
+ color: var(--loki-text-muted);
401
+ cursor: pointer;
402
+ padding: 4px;
403
+ font-size: 18px;
404
+ line-height: 1;
405
+ }
406
+
407
+ .shortcuts-close:hover {
408
+ color: var(--loki-text-primary);
409
+ }
410
+
411
+ .shortcuts-group {
412
+ margin-bottom: 16px;
413
+ }
414
+
415
+ .shortcuts-group-title {
416
+ font-size: 11px;
417
+ font-weight: 600;
418
+ text-transform: uppercase;
419
+ letter-spacing: 0.5px;
420
+ color: var(--loki-text-muted);
421
+ margin-bottom: 8px;
422
+ }
423
+
424
+ .shortcut-row {
425
+ display: flex;
426
+ justify-content: space-between;
427
+ align-items: center;
428
+ padding: 4px 0;
429
+ }
430
+
431
+ .shortcut-keys {
432
+ display: flex;
433
+ gap: 4px;
434
+ }
435
+
436
+ .shortcut-key {
437
+ display: inline-block;
438
+ padding: 2px 8px;
439
+ background: var(--loki-bg-tertiary);
440
+ border: 1px solid var(--loki-border);
441
+ border-radius: 4px;
442
+ font-size: 12px;
443
+ font-family: 'JetBrains Mono', monospace;
444
+ color: var(--loki-text-primary);
445
+ min-width: 24px;
446
+ text-align: center;
447
+ }
448
+
449
+ .shortcut-desc {
450
+ font-size: 13px;
451
+ color: var(--loki-text-secondary);
452
+ }
354
453
  </style>
355
454
  </head>
356
455
  <body>
@@ -411,7 +510,9 @@
411
510
  <div class="sidebar-controls">
412
511
  <input type="text" class="api-url-input" id="api-url" placeholder="API URL">
413
512
  <button class="api-btn" id="connect-btn">Go</button>
414
- <button class="theme-toggle" id="theme-toggle">
513
+ <button class="theme-toggle" id="theme-toggle" title="Toggle theme (T)">
514
+ <svg id="theme-icon-sun" width="14" height="14" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" fill="none" style="display:none"><circle cx="12" cy="12" r="5"/><line x1="12" y1="1" x2="12" y2="3"/><line x1="12" y1="21" x2="12" y2="23"/><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"/><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"/><line x1="1" y1="12" x2="3" y2="12"/><line x1="21" y1="12" x2="23" y2="12"/><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"/><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"/></svg>
515
+ <svg id="theme-icon-moon" width="14" height="14" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" fill="none" style="display:none"><path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"/></svg>
415
516
  <span id="theme-label">Dark</span>
416
517
  </button>
417
518
  </div>
@@ -475,6 +576,39 @@
475
576
  </main>
476
577
  </div>
477
578
 
579
+ <!-- Keyboard Shortcuts Help Overlay -->
580
+ <div class="shortcuts-overlay" id="shortcuts-overlay">
581
+ <div class="shortcuts-dialog">
582
+ <div class="shortcuts-header">
583
+ <span class="shortcuts-title">Keyboard Shortcuts</span>
584
+ <button class="shortcuts-close" id="shortcuts-close" aria-label="Close">&times;</button>
585
+ </div>
586
+ <div class="shortcuts-group">
587
+ <div class="shortcuts-group-title">Navigation</div>
588
+ <div class="shortcut-row"><span class="shortcut-desc">Overview</span><span class="shortcut-keys"><kbd class="shortcut-key">1</kbd></span></div>
589
+ <div class="shortcut-row"><span class="shortcut-desc">Tasks</span><span class="shortcut-keys"><kbd class="shortcut-key">2</kbd></span></div>
590
+ <div class="shortcut-row"><span class="shortcut-desc">Logs</span><span class="shortcut-keys"><kbd class="shortcut-key">3</kbd></span></div>
591
+ <div class="shortcut-row"><span class="shortcut-desc">Memory</span><span class="shortcut-keys"><kbd class="shortcut-key">4</kbd></span></div>
592
+ <div class="shortcut-row"><span class="shortcut-desc">Learning</span><span class="shortcut-keys"><kbd class="shortcut-key">5</kbd></span></div>
593
+ <div class="shortcut-row"><span class="shortcut-desc">Council</span><span class="shortcut-keys"><kbd class="shortcut-key">6</kbd></span></div>
594
+ <div class="shortcut-row"><span class="shortcut-desc">Cost</span><span class="shortcut-keys"><kbd class="shortcut-key">7</kbd></span></div>
595
+ </div>
596
+ <div class="shortcuts-group">
597
+ <div class="shortcuts-group-title">Session</div>
598
+ <div class="shortcut-row"><span class="shortcut-desc">Pause session</span><span class="shortcut-keys"><kbd class="shortcut-key">p</kbd></span></div>
599
+ <div class="shortcut-row"><span class="shortcut-desc">Resume session</span><span class="shortcut-keys"><kbd class="shortcut-key">r</kbd></span></div>
600
+ <div class="shortcut-row"><span class="shortcut-desc">Stop session</span><span class="shortcut-keys"><kbd class="shortcut-key">s</kbd></span></div>
601
+ </div>
602
+ <div class="shortcuts-group">
603
+ <div class="shortcuts-group-title">General</div>
604
+ <div class="shortcut-row"><span class="shortcut-desc">Toggle theme</span><span class="shortcut-keys"><kbd class="shortcut-key">t</kbd></span></div>
605
+ <div class="shortcut-row"><span class="shortcut-desc">Focus API URL</span><span class="shortcut-keys"><kbd class="shortcut-key">/</kbd></span></div>
606
+ <div class="shortcut-row"><span class="shortcut-desc">Show shortcuts</span><span class="shortcut-keys"><kbd class="shortcut-key">?</kbd></span></div>
607
+ <div class="shortcut-row"><span class="shortcut-desc">Close overlay</span><span class="shortcut-keys"><kbd class="shortcut-key">Esc</kbd></span></div>
608
+ </div>
609
+ </div>
610
+ </div>
611
+
478
612
  <!-- Inlined JavaScript Bundle -->
479
613
  <script>
480
614
  var LokiDashboard=(()=>{var N=Object.defineProperty;var se=Object.getOwnPropertyDescriptor;var re=Object.getOwnPropertyNames;var oe=Object.prototype.hasOwnProperty;var ne=(l,e,t)=>e in l?N(l,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):l[e]=t;var le=(l,e)=>{for(var t in e)N(l,t,{get:e[t],enumerable:!0})},de=(l,e,t,a)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of re(e))!oe.call(l,i)&&i!==t&&N(l,i,{get:()=>e[i],enumerable:!(a=se(e,i))||a.enumerable});return l};var ce=l=>de(N({},"__esModule",{value:!0}),l);var k=(l,e,t)=>ne(l,typeof e!="symbol"?e+"":e,t);var _e={};le(_e,{ANIMATION:()=>w,ARIA_PATTERNS:()=>G,ApiEvents:()=>o,BASE_STYLES:()=>I,BREAKPOINTS:()=>q,COMMON_STYLES:()=>X,KEYBOARD_SHORTCUTS:()=>K,KeyboardHandler:()=>A,LokiApiClient:()=>L,LokiCostDashboard:()=>F,LokiCouncilDashboard:()=>O,LokiElement:()=>c,LokiLearningDashboard:()=>H,LokiLogStream:()=>B,LokiMemoryBrowser:()=>U,LokiOverview:()=>M,LokiSessionControl:()=>j,LokiState:()=>R,LokiTaskBoard:()=>z,LokiTheme:()=>T,RADIUS:()=>y,SPACING:()=>_,STATE_CHANGE_EVENT:()=>Y,THEMES:()=>b,THEME_VARIABLES:()=>V,TYPOGRAPHY:()=>v,UnifiedThemeManager:()=>h,VERSION:()=>ke,Z_INDEX:()=>$,createApiClient:()=>ee,createStore:()=>te,generateThemeCSS:()=>m,generateTokensCSS:()=>P,getApiClient:()=>g,getState:()=>C,init:()=>fe});var b={light:{"--loki-bg-primary":"#fafafa","--loki-bg-secondary":"#f4f4f5","--loki-bg-tertiary":"#e4e4e7","--loki-bg-card":"#ffffff","--loki-bg-hover":"#f0f0f3","--loki-bg-active":"#e8e8ec","--loki-bg-overlay":"rgba(0, 0, 0, 0.5)","--loki-accent":"#7c3aed","--loki-accent-hover":"#6d28d9","--loki-accent-active":"#5b21b6","--loki-accent-light":"#8b5cf6","--loki-accent-muted":"rgba(124, 58, 237, 0.12)","--loki-text-primary":"#18181b","--loki-text-secondary":"#52525b","--loki-text-muted":"#a1a1aa","--loki-text-disabled":"#d4d4d8","--loki-text-inverse":"#ffffff","--loki-border":"#e4e4e7","--loki-border-light":"#d4d4d8","--loki-border-focus":"#7c3aed","--loki-success":"#16a34a","--loki-success-muted":"rgba(22, 163, 74, 0.12)","--loki-warning":"#ca8a04","--loki-warning-muted":"rgba(202, 138, 4, 0.12)","--loki-error":"#dc2626","--loki-error-muted":"rgba(220, 38, 38, 0.12)","--loki-info":"#2563eb","--loki-info-muted":"rgba(37, 99, 235, 0.12)","--loki-green":"#16a34a","--loki-green-muted":"rgba(22, 163, 74, 0.12)","--loki-yellow":"#ca8a04","--loki-yellow-muted":"rgba(202, 138, 4, 0.12)","--loki-red":"#dc2626","--loki-red-muted":"rgba(220, 38, 38, 0.12)","--loki-blue":"#2563eb","--loki-blue-muted":"rgba(37, 99, 235, 0.12)","--loki-purple":"#9333ea","--loki-purple-muted":"rgba(147, 51, 234, 0.12)","--loki-opus":"#d97706","--loki-sonnet":"#4f46e5","--loki-haiku":"#059669","--loki-shadow-sm":"0 1px 2px rgba(0, 0, 0, 0.05)","--loki-shadow-md":"0 4px 6px rgba(0, 0, 0, 0.07)","--loki-shadow-lg":"0 10px 15px rgba(0, 0, 0, 0.1)","--loki-shadow-focus":"0 0 0 3px rgba(124, 58, 237, 0.3)"},dark:{"--loki-bg-primary":"#09090b","--loki-bg-secondary":"#0c0c0f","--loki-bg-tertiary":"#111114","--loki-bg-card":"#18181b","--loki-bg-hover":"#1f1f23","--loki-bg-active":"#27272a","--loki-bg-overlay":"rgba(0, 0, 0, 0.8)","--loki-accent":"#8b5cf6","--loki-accent-hover":"#a78bfa","--loki-accent-active":"#7c3aed","--loki-accent-light":"#a78bfa","--loki-accent-muted":"rgba(139, 92, 246, 0.15)","--loki-text-primary":"#fafafa","--loki-text-secondary":"#a1a1aa","--loki-text-muted":"#52525b","--loki-text-disabled":"#3f3f46","--loki-text-inverse":"#09090b","--loki-border":"rgba(255, 255, 255, 0.06)","--loki-border-light":"rgba(255, 255, 255, 0.1)","--loki-border-focus":"#8b5cf6","--loki-success":"#22c55e","--loki-success-muted":"rgba(34, 197, 94, 0.15)","--loki-warning":"#eab308","--loki-warning-muted":"rgba(234, 179, 8, 0.15)","--loki-error":"#ef4444","--loki-error-muted":"rgba(239, 68, 68, 0.15)","--loki-info":"#3b82f6","--loki-info-muted":"rgba(59, 130, 246, 0.15)","--loki-green":"#22c55e","--loki-green-muted":"rgba(34, 197, 94, 0.15)","--loki-yellow":"#eab308","--loki-yellow-muted":"rgba(234, 179, 8, 0.15)","--loki-red":"#ef4444","--loki-red-muted":"rgba(239, 68, 68, 0.15)","--loki-blue":"#3b82f6","--loki-blue-muted":"rgba(59, 130, 246, 0.15)","--loki-purple":"#a78bfa","--loki-purple-muted":"rgba(167, 139, 250, 0.15)","--loki-opus":"#f59e0b","--loki-sonnet":"#818cf8","--loki-haiku":"#34d399","--loki-shadow-sm":"0 1px 2px rgba(0, 0, 0, 0.4)","--loki-shadow-md":"0 4px 12px rgba(0, 0, 0, 0.5)","--loki-shadow-lg":"0 10px 25px rgba(0, 0, 0, 0.6)","--loki-shadow-focus":"0 0 0 3px rgba(139, 92, 246, 0.25)"},"high-contrast":{"--loki-bg-primary":"#000000","--loki-bg-secondary":"#0a0a0a","--loki-bg-tertiary":"#141414","--loki-bg-card":"#0a0a0a","--loki-bg-hover":"#1a1a1a","--loki-bg-active":"#242424","--loki-bg-overlay":"rgba(0, 0, 0, 0.9)","--loki-accent":"#c084fc","--loki-accent-hover":"#d8b4fe","--loki-accent-active":"#e9d5ff","--loki-accent-light":"#d8b4fe","--loki-accent-muted":"rgba(192, 132, 252, 0.25)","--loki-text-primary":"#ffffff","--loki-text-secondary":"#e0e0e0","--loki-text-muted":"#b0b0b0","--loki-text-disabled":"#666666","--loki-text-inverse":"#000000","--loki-border":"#ffffff","--loki-border-light":"#cccccc","--loki-border-focus":"#c084fc","--loki-success":"#4ade80","--loki-success-muted":"rgba(74, 222, 128, 0.25)","--loki-warning":"#fde047","--loki-warning-muted":"rgba(253, 224, 71, 0.25)","--loki-error":"#f87171","--loki-error-muted":"rgba(248, 113, 113, 0.25)","--loki-info":"#60a5fa","--loki-info-muted":"rgba(96, 165, 250, 0.25)","--loki-green":"#4ade80","--loki-green-muted":"rgba(74, 222, 128, 0.25)","--loki-yellow":"#fde047","--loki-yellow-muted":"rgba(253, 224, 71, 0.25)","--loki-red":"#f87171","--loki-red-muted":"rgba(248, 113, 113, 0.25)","--loki-blue":"#60a5fa","--loki-blue-muted":"rgba(96, 165, 250, 0.25)","--loki-purple":"#c084fc","--loki-purple-muted":"rgba(192, 132, 252, 0.25)","--loki-opus":"#fbbf24","--loki-sonnet":"#818cf8","--loki-haiku":"#34d399","--loki-shadow-sm":"none","--loki-shadow-md":"none","--loki-shadow-lg":"none","--loki-shadow-focus":"0 0 0 3px #c084fc"},"vscode-light":{"--loki-bg-primary":"var(--vscode-editor-background, #ffffff)","--loki-bg-secondary":"var(--vscode-sideBar-background, #f3f3f3)","--loki-bg-tertiary":"var(--vscode-input-background, #ffffff)","--loki-bg-card":"var(--vscode-editor-background, #ffffff)","--loki-bg-hover":"var(--vscode-list-hoverBackground, #e8e8e8)","--loki-bg-active":"var(--vscode-list-activeSelectionBackground, #0060c0)","--loki-bg-overlay":"rgba(0, 0, 0, 0.4)","--loki-accent":"var(--vscode-focusBorder, #0066cc)","--loki-accent-hover":"var(--vscode-button-hoverBackground, #0055aa)","--loki-accent-active":"var(--vscode-button-background, #007acc)","--loki-accent-light":"var(--vscode-focusBorder, #0066cc)","--loki-accent-muted":"var(--vscode-editor-selectionBackground, rgba(0, 102, 204, 0.2))","--loki-text-primary":"var(--vscode-foreground, #333333)","--loki-text-secondary":"var(--vscode-descriptionForeground, #717171)","--loki-text-muted":"var(--vscode-disabledForeground, #a0a0a0)","--loki-text-disabled":"var(--vscode-disabledForeground, #cccccc)","--loki-text-inverse":"var(--vscode-button-foreground, #ffffff)","--loki-border":"var(--vscode-widget-border, #c8c8c8)","--loki-border-light":"var(--vscode-widget-border, #e0e0e0)","--loki-border-focus":"var(--vscode-focusBorder, #0066cc)","--loki-success":"var(--vscode-testing-iconPassed, #388a34)","--loki-success-muted":"rgba(56, 138, 52, 0.15)","--loki-warning":"var(--vscode-editorWarning-foreground, #bf8803)","--loki-warning-muted":"rgba(191, 136, 3, 0.15)","--loki-error":"var(--vscode-errorForeground, #e51400)","--loki-error-muted":"rgba(229, 20, 0, 0.15)","--loki-info":"var(--vscode-editorInfo-foreground, #1a85ff)","--loki-info-muted":"rgba(26, 133, 255, 0.15)","--loki-green":"var(--vscode-testing-iconPassed, #388a34)","--loki-green-muted":"rgba(56, 138, 52, 0.15)","--loki-yellow":"var(--vscode-editorWarning-foreground, #bf8803)","--loki-yellow-muted":"rgba(191, 136, 3, 0.15)","--loki-red":"var(--vscode-errorForeground, #e51400)","--loki-red-muted":"rgba(229, 20, 0, 0.15)","--loki-blue":"var(--vscode-editorInfo-foreground, #1a85ff)","--loki-blue-muted":"rgba(26, 133, 255, 0.15)","--loki-purple":"#9333ea","--loki-purple-muted":"rgba(147, 51, 234, 0.15)","--loki-opus":"#d97706","--loki-sonnet":"#4f46e5","--loki-haiku":"#059669","--loki-shadow-sm":"0 1px 2px rgba(0, 0, 0, 0.05)","--loki-shadow-md":"0 2px 4px rgba(0, 0, 0, 0.1)","--loki-shadow-lg":"0 4px 8px rgba(0, 0, 0, 0.15)","--loki-shadow-focus":"0 0 0 2px var(--vscode-focusBorder, #0066cc)"},"vscode-dark":{"--loki-bg-primary":"var(--vscode-editor-background, #1e1e1e)","--loki-bg-secondary":"var(--vscode-sideBar-background, #252526)","--loki-bg-tertiary":"var(--vscode-input-background, #3c3c3c)","--loki-bg-card":"var(--vscode-editor-background, #1e1e1e)","--loki-bg-hover":"var(--vscode-list-hoverBackground, #2a2d2e)","--loki-bg-active":"var(--vscode-list-activeSelectionBackground, #094771)","--loki-bg-overlay":"rgba(0, 0, 0, 0.6)","--loki-accent":"var(--vscode-focusBorder, #007fd4)","--loki-accent-hover":"var(--vscode-button-hoverBackground, #1177bb)","--loki-accent-active":"var(--vscode-button-background, #0e639c)","--loki-accent-light":"var(--vscode-focusBorder, #007fd4)","--loki-accent-muted":"var(--vscode-editor-selectionBackground, rgba(0, 127, 212, 0.25))","--loki-text-primary":"var(--vscode-foreground, #cccccc)","--loki-text-secondary":"var(--vscode-descriptionForeground, #9d9d9d)","--loki-text-muted":"var(--vscode-disabledForeground, #6b6b6b)","--loki-text-disabled":"var(--vscode-disabledForeground, #4d4d4d)","--loki-text-inverse":"var(--vscode-button-foreground, #ffffff)","--loki-border":"var(--vscode-widget-border, #454545)","--loki-border-light":"var(--vscode-widget-border, #5a5a5a)","--loki-border-focus":"var(--vscode-focusBorder, #007fd4)","--loki-success":"var(--vscode-testing-iconPassed, #89d185)","--loki-success-muted":"rgba(137, 209, 133, 0.2)","--loki-warning":"var(--vscode-editorWarning-foreground, #cca700)","--loki-warning-muted":"rgba(204, 167, 0, 0.2)","--loki-error":"var(--vscode-errorForeground, #f48771)","--loki-error-muted":"rgba(244, 135, 113, 0.2)","--loki-info":"var(--vscode-editorInfo-foreground, #75beff)","--loki-info-muted":"rgba(117, 190, 255, 0.2)","--loki-green":"var(--vscode-testing-iconPassed, #89d185)","--loki-green-muted":"rgba(137, 209, 133, 0.2)","--loki-yellow":"var(--vscode-editorWarning-foreground, #cca700)","--loki-yellow-muted":"rgba(204, 167, 0, 0.2)","--loki-red":"var(--vscode-errorForeground, #f48771)","--loki-red-muted":"rgba(244, 135, 113, 0.2)","--loki-blue":"var(--vscode-editorInfo-foreground, #75beff)","--loki-blue-muted":"rgba(117, 190, 255, 0.2)","--loki-purple":"#c084fc","--loki-purple-muted":"rgba(192, 132, 252, 0.2)","--loki-opus":"#f59e0b","--loki-sonnet":"#818cf8","--loki-haiku":"#34d399","--loki-shadow-sm":"0 1px 2px rgba(0, 0, 0, 0.3)","--loki-shadow-md":"0 2px 4px rgba(0, 0, 0, 0.4)","--loki-shadow-lg":"0 4px 8px rgba(0, 0, 0, 0.5)","--loki-shadow-focus":"0 0 0 2px var(--vscode-focusBorder, #007fd4)"}},_={xs:"4px",sm:"8px",md:"12px",lg:"16px",xl:"24px","2xl":"32px","3xl":"48px"},y={none:"0",sm:"4px",md:"6px",lg:"8px",xl:"10px",full:"9999px"},v={fontFamily:{sans:"'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",mono:"'JetBrains Mono', 'Fira Code', 'SF Mono', Menlo, monospace"},fontSize:{xs:"10px",sm:"11px",base:"12px",md:"13px",lg:"14px",xl:"16px","2xl":"18px","3xl":"24px"},fontWeight:{normal:"400",medium:"500",semibold:"600",bold:"700"},lineHeight:{tight:"1.25",normal:"1.5",relaxed:"1.75"}},w={duration:{fast:"100ms",normal:"200ms",slow:"300ms",slower:"500ms"},easing:{default:"cubic-bezier(0.4, 0, 0.2, 1)",in:"cubic-bezier(0.4, 0, 1, 1)",out:"cubic-bezier(0, 0, 0.2, 1)",bounce:"cubic-bezier(0.68, -0.55, 0.265, 1.55)"}},q={sm:"640px",md:"768px",lg:"1024px",xl:"1280px","2xl":"1536px"},$={base:"0",dropdown:"100",sticky:"200",modal:"300",popover:"400",tooltip:"500",toast:"600"},K={"navigation.nextItem":{key:"ArrowDown",modifiers:[]},"navigation.prevItem":{key:"ArrowUp",modifiers:[]},"navigation.nextSection":{key:"Tab",modifiers:[]},"navigation.prevSection":{key:"Tab",modifiers:["Shift"]},"navigation.confirm":{key:"Enter",modifiers:[]},"navigation.cancel":{key:"Escape",modifiers:[]},"action.refresh":{key:"r",modifiers:["Meta"]},"action.search":{key:"k",modifiers:["Meta"]},"action.save":{key:"s",modifiers:["Meta"]},"action.close":{key:"w",modifiers:["Meta"]},"theme.toggle":{key:"d",modifiers:["Meta","Shift"]},"task.create":{key:"n",modifiers:["Meta"]},"task.complete":{key:"Enter",modifiers:["Meta"]},"view.toggleLogs":{key:"l",modifiers:["Meta","Shift"]},"view.toggleMemory":{key:"m",modifiers:["Meta","Shift"]}},G={button:{role:"button",tabIndex:0},tablist:{role:"tablist"},tab:{role:"tab",ariaSelected:!1,tabIndex:-1},tabpanel:{role:"tabpanel",tabIndex:0},list:{role:"list"},listitem:{role:"listitem"},livePolite:{ariaLive:"polite",ariaAtomic:!0},liveAssertive:{ariaLive:"assertive",ariaAtomic:!0},dialog:{role:"dialog",ariaModal:!0},alertdialog:{role:"alertdialog",ariaModal:!0},status:{role:"status",ariaLive:"polite"},alert:{role:"alert",ariaLive:"assertive"},log:{role:"log",ariaLive:"polite",ariaRelevant:"additions"}};function m(l){let e=b[l];return e?Object.entries(e).map(([t,a])=>`${t}: ${a};`).join(`
@@ -4613,18 +4747,27 @@ document.addEventListener('DOMContentLoaded', function() {
4613
4747
  var themeToggle = document.getElementById('theme-toggle');
4614
4748
  var themeLabel = document.getElementById('theme-label');
4615
4749
 
4616
- function updateThemeLabel() {
4750
+ var sunIcon = document.getElementById('theme-icon-sun');
4751
+ var moonIcon = document.getElementById('theme-icon-moon');
4752
+
4753
+ function updateThemeUI() {
4617
4754
  var theme = LokiDashboard.UnifiedThemeManager.getTheme();
4618
- themeLabel.textContent = theme.includes('dark') ? 'Light' : 'Dark';
4755
+ var isDark = theme.includes('dark') || theme === 'high-contrast';
4756
+ themeLabel.textContent = isDark ? 'Light' : 'Dark';
4757
+ if (sunIcon) sunIcon.style.display = isDark ? 'inline' : 'none';
4758
+ if (moonIcon) moonIcon.style.display = isDark ? 'none' : 'inline';
4619
4759
  }
4620
4760
 
4621
4761
  themeToggle.addEventListener('click', function() {
4622
4762
  LokiDashboard.UnifiedThemeManager.toggle();
4623
- updateThemeLabel();
4763
+ updateThemeUI();
4624
4764
  });
4625
4765
 
4626
- // Initialize theme label
4627
- updateThemeLabel();
4766
+ window.addEventListener('loki-theme-change', function() {
4767
+ updateThemeUI();
4768
+ });
4769
+
4770
+ updateThemeUI();
4628
4771
 
4629
4772
  // API URL configuration - auto-detect from current server
4630
4773
  var apiUrlInput = document.getElementById('api-url');
@@ -4736,6 +4879,116 @@ document.addEventListener('DOMContentLoaded', function() {
4736
4879
  }
4737
4880
  });
4738
4881
 
4882
+ // --- Keyboard Shortcuts (Issue #18) ---
4883
+ var shortcutsOverlay = document.getElementById('shortcuts-overlay');
4884
+ var shortcutsClose = document.getElementById('shortcuts-close');
4885
+
4886
+ function toggleShortcutsOverlay() {
4887
+ shortcutsOverlay.classList.toggle('visible');
4888
+ }
4889
+
4890
+ function closeShortcutsOverlay() {
4891
+ shortcutsOverlay.classList.remove('visible');
4892
+ }
4893
+
4894
+ shortcutsClose.addEventListener('click', closeShortcutsOverlay);
4895
+
4896
+ // Close overlay when clicking outside the dialog
4897
+ shortcutsOverlay.addEventListener('click', function(e) {
4898
+ if (e.target === shortcutsOverlay) {
4899
+ closeShortcutsOverlay();
4900
+ }
4901
+ });
4902
+
4903
+ document.addEventListener('keydown', function(e) {
4904
+ // Skip shortcuts when typing in input, textarea, or select elements
4905
+ var tag = (e.target.tagName || '').toLowerCase();
4906
+ if (tag === 'input' || tag === 'textarea' || tag === 'select' || e.target.isContentEditable) {
4907
+ // Allow Escape to blur input fields
4908
+ if (e.key === 'Escape') {
4909
+ e.target.blur();
4910
+ }
4911
+ return;
4912
+ }
4913
+
4914
+ // Skip if modifier keys are held (let browser defaults work)
4915
+ if (e.metaKey || e.ctrlKey || e.altKey) return;
4916
+
4917
+ var sections = ['overview', 'tasks', 'logs', 'memory', 'learning', 'council', 'cost'];
4918
+
4919
+ switch (e.key) {
4920
+ // Section navigation: 1-7
4921
+ case '1': case '2': case '3': case '4': case '5': case '6': case '7':
4922
+ e.preventDefault();
4923
+ switchSection(sections[parseInt(e.key) - 1]);
4924
+ break;
4925
+
4926
+ // Help overlay
4927
+ case '?':
4928
+ e.preventDefault();
4929
+ toggleShortcutsOverlay();
4930
+ break;
4931
+
4932
+ // Close overlays
4933
+ case 'Escape':
4934
+ if (shortcutsOverlay.classList.contains('visible')) {
4935
+ e.preventDefault();
4936
+ closeShortcutsOverlay();
4937
+ }
4938
+ break;
4939
+
4940
+ // Focus API URL input
4941
+ case '/':
4942
+ e.preventDefault();
4943
+ apiUrlInput.focus();
4944
+ apiUrlInput.select();
4945
+ break;
4946
+
4947
+ // Theme toggle
4948
+ case 't':
4949
+ e.preventDefault();
4950
+ LokiDashboard.UnifiedThemeManager.toggle();
4951
+ updateThemeLabel();
4952
+ break;
4953
+
4954
+ // Session controls
4955
+ case 'p':
4956
+ e.preventDefault();
4957
+ var sessionCtrl = document.getElementById('session-control');
4958
+ if (sessionCtrl) {
4959
+ var pauseBtn = sessionCtrl.shadowRoot && sessionCtrl.shadowRoot.getElementById('pause-btn');
4960
+ if (pauseBtn && !pauseBtn.disabled) {
4961
+ pauseBtn.click();
4962
+ }
4963
+ }
4964
+ break;
4965
+
4966
+ case 'r':
4967
+ e.preventDefault();
4968
+ var sessionCtrl2 = document.getElementById('session-control');
4969
+ if (sessionCtrl2) {
4970
+ var resumeBtn = sessionCtrl2.shadowRoot && sessionCtrl2.shadowRoot.getElementById('resume-btn');
4971
+ if (resumeBtn) {
4972
+ resumeBtn.click();
4973
+ }
4974
+ }
4975
+ break;
4976
+
4977
+ case 's':
4978
+ e.preventDefault();
4979
+ var sessionCtrl3 = document.getElementById('session-control');
4980
+ if (sessionCtrl3) {
4981
+ var stopBtn = sessionCtrl3.shadowRoot && sessionCtrl3.shadowRoot.getElementById('stop-btn');
4982
+ if (stopBtn && !stopBtn.disabled) {
4983
+ if (window.confirm('Are you sure you want to stop the session?')) {
4984
+ stopBtn.click();
4985
+ }
4986
+ }
4987
+ }
4988
+ break;
4989
+ }
4990
+ });
4991
+
4739
4992
  // Restore last section from localStorage
4740
4993
  var savedSection = localStorage.getItem('loki-active-section');
4741
4994
  if (savedSection) {
@@ -2,7 +2,7 @@
2
2
 
3
3
  Complete installation instructions for all platforms and use cases.
4
4
 
5
- **Version:** v5.30.0
5
+ **Version:** v5.32.0
6
6
 
7
7
  ---
8
8
 
@@ -20,6 +20,7 @@ Complete installation instructions for all platforms and use cases.
20
20
  - [Anthropic API Console](#anthropic-api-console)
21
21
  - [Verify Installation](#verify-installation)
22
22
  - [Ports](#ports)
23
+ - [Shell Completions](#shell-completions)
23
24
  - [Troubleshooting](#troubleshooting)
24
25
 
25
26
  ---
@@ -36,7 +37,7 @@ npm install -g loki-mode
36
37
  brew tap asklokesh/tap && brew install loki-mode
37
38
 
38
39
  # Option C: Docker
39
- docker pull asklokesh/loki-mode:5.30.0
40
+ docker pull asklokesh/loki-mode:5.32.0
40
41
 
41
42
  # Option D: Git clone
42
43
  git clone https://github.com/asklokesh/loki-mode.git ~/.claude/skills/loki-mode
@@ -227,7 +228,7 @@ Run Loki Mode in a container for isolated execution.
227
228
 
228
229
  ```bash
229
230
  # Pull the image
230
- docker pull asklokesh/loki-mode:5.30.0
231
+ docker pull asklokesh/loki-mode:5.32.0
231
232
 
232
233
  # Or use docker-compose
233
234
  curl -o docker-compose.yml https://raw.githubusercontent.com/asklokesh/loki-mode/main/docker-compose.yml
@@ -237,10 +238,10 @@ curl -o docker-compose.yml https://raw.githubusercontent.com/asklokesh/loki-mode
237
238
 
238
239
  ```bash
239
240
  # Run with a PRD file
240
- docker run -v $(pwd):/workspace -w /workspace asklokesh/loki-mode:5.30.0 start ./my-prd.md
241
+ docker run -v $(pwd):/workspace -w /workspace asklokesh/loki-mode:5.32.0 start ./my-prd.md
241
242
 
242
243
  # Interactive mode
243
- docker run -it -v $(pwd):/workspace -w /workspace asklokesh/loki-mode:5.30.0
244
+ docker run -it -v $(pwd):/workspace -w /workspace asklokesh/loki-mode:5.32.0
244
245
 
245
246
  # Using docker-compose
246
247
  docker-compose run loki start ./my-prd.md
@@ -253,7 +254,7 @@ Pass your configuration via environment variables:
253
254
  ```bash
254
255
  docker run -e LOKI_MAX_RETRIES=100 -e LOKI_BASE_WAIT=120 \
255
256
  -v $(pwd):/workspace -w /workspace \
256
- asklokesh/loki-mode:5.30.0 start ./my-prd.md
257
+ asklokesh/loki-mode:5.32.0 start ./my-prd.md
257
258
  ```
258
259
 
259
260
  ### Updating
@@ -369,12 +370,12 @@ Pass the provider as an environment variable:
369
370
  # Use Codex with Docker
370
371
  docker run -e LOKI_PROVIDER=codex \
371
372
  -v $(pwd):/workspace -w /workspace \
372
- asklokesh/loki-mode:5.30.0 start ./my-prd.md
373
+ asklokesh/loki-mode:5.32.0 start ./my-prd.md
373
374
 
374
375
  # Use Gemini with Docker
375
376
  docker run -e LOKI_PROVIDER=gemini \
376
377
  -v $(pwd):/workspace -w /workspace \
377
- asklokesh/loki-mode:5.30.0 start ./my-prd.md
378
+ asklokesh/loki-mode:5.32.0 start ./my-prd.md
378
379
  ```
379
380
 
380
381
  ### Degraded Mode
@@ -611,6 +612,107 @@ CORS_ALLOWED_ORIGINS="http://localhost:3000,https://my-dashboard.example.com" lo
611
612
 
612
613
  ---
613
614
 
615
+ ## Shell Completions
616
+
617
+ Enable tab completion for the `loki` CLI to support subcommands, flags, and file arguments.
618
+
619
+ ---
620
+
621
+ ## Bash Setup
622
+
623
+ ### Option 1: Permanent Setup (Recommended)
624
+
625
+ Add the source command to your startup file so completions load every time you open a terminal.
626
+
627
+ Add this line to your `~/.bashrc` (Linux) or `~/.bash_profile` (macOS):
628
+
629
+ ```bash
630
+ source /path/to/loki/completions/loki.bash
631
+ ```
632
+
633
+ ---
634
+
635
+ ### Option 2: Manual Sourcing (Temporary)
636
+
637
+ If you only want to enable completions for your current terminal session (for example, for testing), run:
638
+
639
+ ```bash
640
+ source completions/loki.bash
641
+ ```
642
+
643
+ ---
644
+
645
+ ### Optional: Smoother Bash Experience
646
+
647
+ By default, Bash requires two **TAB** presses to show the completion menu. To make it instant (similar to Zsh) and cycle through options more easily, add the following lines to your `~/.inputrc` file:
648
+
649
+ ```bash
650
+ # Show menu immediately on first TAB
651
+ set show-all-if-ambiguous on
652
+
653
+ # Case-insensitive completion (optional)
654
+ set completion-ignore-case on
655
+ ```
656
+
657
+ > **Note:** You will need to restart your terminal for `~/.inputrc` changes to take effect.
658
+
659
+ ---
660
+
661
+ ## Zsh Setup
662
+
663
+ Zsh completions require the script to be located in a directory listed in your `$fpath`.
664
+
665
+ ### Permanent Setup
666
+
667
+ Add the `loki` completions directory to your `$fpath` in `~/.zshrc` **before** initializing completions:
668
+
669
+ ```bash
670
+ # 1. Add the completions directory to fpath
671
+ fpath=(/path/to/loki/completions $fpath)
672
+
673
+ # 2. Initialize completions
674
+ autoload -Uz compinit && compinit
675
+ ```
676
+
677
+ ---
678
+
679
+ ## Testing Completions
680
+
681
+ After installation, restart your shell or source your configuration file, then verify:
682
+
683
+ ### Bash
684
+
685
+ ```bash
686
+ loki <TAB> # Should immediately list subcommands
687
+ loki start -<TAB> # Should list flags (--provider, --parallel, etc.)
688
+ ```
689
+
690
+ ### Zsh
691
+
692
+ ```bash
693
+ loki <TAB> # Should show subcommands with descriptions
694
+ loki start --pro<TAB> # Should autocomplete to --provider
695
+ ```
696
+
697
+ ---
698
+
699
+ ## Completion Features
700
+
701
+ The completion scripts support:
702
+
703
+ * **Subcommands**
704
+ `start`, `stop`, `pause`, `resume`, `status`, `dashboard`, `import`, `council`, `memory`, `provider`, `config`, `help`, `completions`
705
+
706
+ * **Smart Context**
707
+
708
+ * `loki start --provider <TAB>` shows only installed providers (`claude`, `codex`, `gemini`).
709
+ * `loki start <TAB>` defaults to file completion for PRD templates.
710
+
711
+ * **Nested Commands**
712
+ Handles specific subcommands for `council`, `memory`, and `config`.
713
+
714
+ ---
715
+
614
716
  ## Troubleshooting
615
717
 
616
718
  ### Skill Not Found
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loki-mode",
3
- "version": "5.30.0",
3
+ "version": "5.32.0",
4
4
  "description": "Multi-agent autonomous startup system for Claude Code, Codex CLI, and Gemini CLI",
5
5
  "keywords": [
6
6
  "claude",
@@ -27,6 +27,7 @@ claude --dangerously-skip-permissions
27
27
 
28
28
  | Template | Description | Tech Stack | Est. Time |
29
29
  |----------|-------------|------------|-----------|
30
+ | [rest-api-auth.md](rest-api-auth.md) | REST API with JWT auth, registration, login, refresh, rate limiting | Express/FastAPI, PostgreSQL, JWT, bcrypt | 30-45 min |
30
31
  | [full-stack-demo.md](full-stack-demo.md) | Bookmark manager with tags, search, and filtering | React, Express, SQLite, TailwindCSS | 30-60 min |
31
32
  | [cli-tool.md](cli-tool.md) | File organizer CLI with subcommands, config, watch mode, undo | Node.js, Commander.js, chalk, chokidar | 30-45 min |
32
33
  | [discord-bot.md](discord-bot.md) | Moderation bot with slash commands, auto-mod, reaction roles | discord.js, SQLite, node-cron | 45-60 min |
@@ -69,7 +70,7 @@ Every template follows a consistent structure:
69
70
 
70
71
  **Testing specific agent types:**
71
72
  - Frontend agent: `static-landing-page.md`, `chrome-extension.md`
72
- - Backend agent: `api-only.md`, `discord-bot.md`
73
+ - Backend agent: `api-only.md`, `rest-api-auth.md`, `discord-bot.md`
73
74
  - Full-stack agent: `full-stack-demo.md`, `blog-platform.md`
74
75
  - DevOps/CLI agent: `cli-tool.md`
75
76
  - Mobile agent: `mobile-app.md`