loki-mode 6.37.6 → 6.37.8

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 minimal human intervention. Requires --dangerously-skip-permissions flag.
4
4
  ---
5
5
 
6
- # Loki Mode v6.37.6
6
+ # Loki Mode v6.37.8
7
7
 
8
8
  **You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
9
9
 
@@ -267,4 +267,4 @@ The following features are documented in skill modules but not yet fully automat
267
267
  | Quality gates 3-reviewer system | Implemented (v5.35.0) | 5 specialist reviewers in `skills/quality-gates.md`; execution in run.sh |
268
268
  | Benchmarks (HumanEval, SWE-bench) | Infrastructure only | Runner scripts and datasets exist in `benchmarks/`; no published results |
269
269
 
270
- **v6.37.6 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
270
+ **v6.37.8 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
package/VERSION CHANGED
@@ -1 +1 @@
1
- 6.37.6
1
+ 6.37.8
package/autonomy/loki CHANGED
@@ -410,7 +410,7 @@ show_help() {
410
410
  echo " api [cmd] Dashboard/API server (start|stop|status)"
411
411
  echo " sandbox [cmd] Docker sandbox (start|stop|status|logs|shell|build)"
412
412
  echo " notify [cmd] Send notifications (test|slack|discord|webhook|status)"
413
- echo " voice [cmd] Voice input for PRD creation (status|listen|dictate|speak|start)"
413
+ echo " telemetry [cmd] OpenTelemetry management (status|enable|disable|stop|start)"
414
414
  echo " import Import GitHub issues as tasks"
415
415
  echo " github [cmd] GitHub integration (sync|export|pr|status)"
416
416
  echo " config [cmd] Manage configuration (show|init|edit|path|set|get)"
@@ -9744,7 +9744,8 @@ main() {
9744
9744
  cmd_enterprise "$@"
9745
9745
  ;;
9746
9746
  voice)
9747
- cmd_voice "$@"
9747
+ echo "Voice mode is planned for a future release. Track progress at github.com/asklokesh/loki-mode/issues/85"
9748
+ exit 0
9748
9749
  ;;
9749
9750
  secrets)
9750
9751
  cmd_secrets "$@"
@@ -13176,95 +13177,9 @@ for check, passed in checks.items():
13176
13177
 
13177
13178
  # Voice input commands
13178
13179
  cmd_voice() {
13179
- local subcommand="${1:-status}"
13180
- local VOICE_SCRIPT="$SKILL_DIR/autonomy/voice.sh"
13181
-
13182
- # Check fallback locations for voice script
13183
- if [ ! -f "$VOICE_SCRIPT" ]; then
13184
- # Try relative to loki CLI location
13185
- local loki_dir
13186
- loki_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
13187
- VOICE_SCRIPT="$loki_dir/voice.sh"
13188
- fi
13189
-
13190
- if [ ! -f "$VOICE_SCRIPT" ]; then
13191
- echo -e "${RED}Error: Voice module not found${NC}"
13192
- echo "Expected at: $SKILL_DIR/autonomy/voice.sh"
13193
- echo ""
13194
- echo "Voice input requires the voice.sh module."
13195
- echo "This feature may not be available in all installations."
13196
- exit 1
13197
- fi
13198
-
13199
- case "$subcommand" in
13200
- status)
13201
- "$VOICE_SCRIPT" status
13202
- ;;
13203
- listen)
13204
- echo -e "${BOLD}Starting voice input...${NC}"
13205
- local text
13206
- text=$("$VOICE_SCRIPT" listen)
13207
- if [ -n "$text" ]; then
13208
- echo ""
13209
- echo -e "${GREEN}Transcribed text:${NC}"
13210
- echo "$text"
13211
- fi
13212
- ;;
13213
- dictate)
13214
- local output="${2:-prd-voice.md}"
13215
- echo -e "${BOLD}Starting guided PRD dictation...${NC}"
13216
- echo ""
13217
- "$VOICE_SCRIPT" dictate "$output"
13218
- if [ -f "$output" ]; then
13219
- echo ""
13220
- echo -e "${GREEN}PRD created: $output${NC}"
13221
- echo ""
13222
- echo "Start Loki Mode with:"
13223
- echo " loki start $output"
13224
- fi
13225
- ;;
13226
- speak)
13227
- shift
13228
- if [ $# -eq 0 ]; then
13229
- echo -e "${RED}Usage: loki voice speak MESSAGE${NC}"
13230
- exit 1
13231
- fi
13232
- "$VOICE_SCRIPT" speak "$*"
13233
- ;;
13234
- start)
13235
- # Dictate PRD and start Loki Mode
13236
- local prd_file="${2:-prd-voice-$(date +%Y%m%d%H%M%S).md}"
13237
- echo -e "${BOLD}Voice-activated PRD creation...${NC}"
13238
- "$VOICE_SCRIPT" dictate "$prd_file"
13239
- if [ -f "$prd_file" ]; then
13240
- echo ""
13241
- echo -e "${GREEN}PRD created. Starting Loki Mode...${NC}"
13242
- cmd_start "$prd_file"
13243
- fi
13244
- ;;
13245
- --help|-h|help)
13246
- echo -e "${BOLD}loki voice${NC} - Voice input for PRD creation"
13247
- echo ""
13248
- echo "Usage: loki voice <command> [options]"
13249
- echo ""
13250
- echo "Commands:"
13251
- echo " status Check voice input capabilities"
13252
- echo " listen Listen and transcribe voice input"
13253
- echo " dictate [FILE] Guided PRD dictation (default: prd-voice.md)"
13254
- echo " speak MESSAGE Text-to-speech output"
13255
- echo " start [FILE] Dictate PRD and start Loki Mode immediately"
13256
- echo ""
13257
- echo "Requirements:"
13258
- echo " macOS: Enable Dictation in System Settings > Keyboard"
13259
- echo " Or: Set OPENAI_API_KEY for Whisper API transcription"
13260
- echo " Or: pip install openai-whisper for local transcription"
13261
- ;;
13262
- *)
13263
- echo -e "${RED}Unknown voice command: $subcommand${NC}"
13264
- echo "Run 'loki voice help' for usage."
13265
- exit 1
13266
- ;;
13267
- esac
13180
+ # Voice mode is planned for a future release (#85)
13181
+ echo "Voice mode is planned for a future release. Track progress at github.com/asklokesh/loki-mode/issues/85"
13182
+ return 0
13268
13183
  }
13269
13184
 
13270
13185
  # Enterprise features (optional - requires env vars)
@@ -13752,9 +13667,22 @@ cmd_telemetry() {
13752
13667
  echo -e "${BOLD}Telemetry Status${NC}"
13753
13668
  echo ""
13754
13669
 
13670
+ # Check persistent opt-out (~/.loki/config)
13671
+ local global_config="${HOME}/.loki/config"
13672
+ local persistently_disabled=false
13673
+ if [ -f "$global_config" ] && grep -q "^TELEMETRY_DISABLED=true" "$global_config" 2>/dev/null; then
13674
+ persistently_disabled=true
13675
+ fi
13676
+
13677
+ if [ "$persistently_disabled" = true ]; then
13678
+ echo -e " Opt-out: ${RED}disabled persistently${NC} (loki telemetry start to re-enable)"
13679
+ fi
13680
+
13755
13681
  local endpoint="${LOKI_OTEL_ENDPOINT:-}"
13756
- if [ -n "$endpoint" ]; then
13682
+ if [ -n "$endpoint" ] && [ "$persistently_disabled" = false ]; then
13757
13683
  echo -e " Endpoint: ${GREEN}$endpoint${NC}"
13684
+ elif [ "$persistently_disabled" = true ]; then
13685
+ echo -e " Endpoint: ${YELLOW}ignored (opted out)${NC}"
13758
13686
  else
13759
13687
  echo -e " Endpoint: ${YELLOW}not configured${NC}"
13760
13688
  fi
@@ -13787,6 +13715,15 @@ try {
13787
13715
 
13788
13716
  enable)
13789
13717
  local endpoint="${1:-http://localhost:4318}"
13718
+
13719
+ # Check persistent opt-out
13720
+ local global_config="${HOME}/.loki/config"
13721
+ if [ -f "$global_config" ] && grep -q "^TELEMETRY_DISABLED=true" "$global_config" 2>/dev/null; then
13722
+ echo -e "${YELLOW}Telemetry is persistently disabled.${NC}"
13723
+ echo "Run 'loki telemetry start' first to re-enable."
13724
+ return 1
13725
+ fi
13726
+
13790
13727
  echo -e "${BOLD}Enabling telemetry${NC}"
13791
13728
 
13792
13729
  # Save to config
@@ -13830,15 +13767,49 @@ with open('$config_file', 'w') as f:
13830
13767
  echo " Unset LOKI_OTEL_ENDPOINT in your shell for immediate effect."
13831
13768
  ;;
13832
13769
 
13770
+ stop)
13771
+ # Persistent opt-out across all sessions
13772
+ local global_config="${HOME}/.loki/config"
13773
+ mkdir -p "${HOME}/.loki"
13774
+
13775
+ # Remove existing TELEMETRY_DISABLED line if present, then add
13776
+ if [ -f "$global_config" ]; then
13777
+ grep -v "^TELEMETRY_DISABLED=" "$global_config" > "${global_config}.tmp" 2>/dev/null || true
13778
+ mv "${global_config}.tmp" "$global_config"
13779
+ fi
13780
+ echo "TELEMETRY_DISABLED=true" >> "$global_config"
13781
+
13782
+ echo -e "${BOLD}Telemetry permanently disabled${NC}"
13783
+ echo ""
13784
+ echo " Opt-out saved to: $global_config"
13785
+ echo " This persists across all sessions and new runs."
13786
+ echo " Run 'loki telemetry start' to re-enable."
13787
+ ;;
13788
+
13789
+ start)
13790
+ # Remove persistent opt-out
13791
+ local global_config="${HOME}/.loki/config"
13792
+ if [ -f "$global_config" ]; then
13793
+ grep -v "^TELEMETRY_DISABLED=" "$global_config" > "${global_config}.tmp" 2>/dev/null || true
13794
+ mv "${global_config}.tmp" "$global_config"
13795
+ fi
13796
+
13797
+ echo -e "${BOLD}Telemetry opt-out removed${NC}"
13798
+ echo ""
13799
+ echo " Telemetry can now be enabled with 'loki telemetry enable [endpoint]'."
13800
+ ;;
13801
+
13833
13802
  --help|-h|help)
13834
- echo -e "${BOLD}loki telemetry${NC} - OpenTelemetry management (v6.7.0)"
13803
+ echo -e "${BOLD}loki telemetry${NC} - OpenTelemetry management"
13835
13804
  echo ""
13836
13805
  echo "Usage: loki telemetry <command>"
13837
13806
  echo ""
13838
13807
  echo "Commands:"
13839
13808
  echo " status Show current telemetry config"
13840
13809
  echo " enable [endpoint] Enable OTEL (default: http://localhost:4318)"
13841
- echo " disable Disable OTEL"
13810
+ echo " disable Disable OTEL for current project"
13811
+ echo " stop Permanently opt out of telemetry across all sessions"
13812
+ echo " start Remove persistent opt-out, re-enable telemetry"
13842
13813
  echo ""
13843
13814
  ;;
13844
13815
  *)
@@ -14648,19 +14619,19 @@ cmd_agent() {
14648
14619
  local filter_swarm="${1:-}"
14649
14620
  echo -e "${BOLD}Agent Types${NC}"
14650
14621
  echo ""
14651
- python3 << PYEOF
14652
- import json, sys
14622
+ TYPES_FILE="$types_file" FILTER_SWARM="$filter_swarm" FILTER_SWARM2="${2:-}" python3 << 'PYEOF'
14623
+ import json, sys, os
14653
14624
 
14654
- with open("$types_file") as f:
14625
+ with open(os.environ["TYPES_FILE"]) as f:
14655
14626
  agents = json.load(f)
14656
14627
 
14657
- filter_swarm = "$filter_swarm"
14628
+ filter_swarm = os.environ.get("FILTER_SWARM", "")
14658
14629
  if filter_swarm and filter_swarm.startswith("--swarm"):
14659
14630
  # Handle --swarm=X or --swarm X
14660
14631
  if "=" in filter_swarm:
14661
14632
  filter_swarm = filter_swarm.split("=")[1]
14662
14633
  else:
14663
- filter_swarm = "${2:-}"
14634
+ filter_swarm = os.environ.get("FILTER_SWARM2", "")
14664
14635
 
14665
14636
  swarms = {}
14666
14637
  for a in agents:
@@ -14690,13 +14661,13 @@ PYEOF
14690
14661
  echo -e "${RED}Usage: loki agent info <type>${NC}"
14691
14662
  return 1
14692
14663
  fi
14693
- python3 << PYEOF
14694
- import json, sys
14664
+ TYPES_FILE="$types_file" AGENT_TYPE="$agent_type" python3 << 'PYEOF'
14665
+ import json, sys, os
14695
14666
 
14696
- with open("$types_file") as f:
14667
+ with open(os.environ["TYPES_FILE"]) as f:
14697
14668
  agents = json.load(f)
14698
14669
 
14699
- target = "$agent_type"
14670
+ target = os.environ["AGENT_TYPE"]
14700
14671
  found = None
14701
14672
  for a in agents:
14702
14673
  if a["type"] == target:
package/autonomy/run.sh CHANGED
@@ -602,6 +602,12 @@ if [ -f "${SCRIPT_DIR}/playwright-verify.sh" ]; then
602
602
  fi
603
603
 
604
604
  # Anonymous usage telemetry (opt-out: LOKI_TELEMETRY_DISABLED=true or DO_NOT_TRACK=1)
605
+ # Also check persistent opt-out from ~/.loki/config (#77)
606
+ if [ -f "${HOME}/.loki/config" ] && grep -q "^TELEMETRY_DISABLED=true" "${HOME}/.loki/config" 2>/dev/null; then
607
+ LOKI_TELEMETRY_DISABLED=true
608
+ export LOKI_TELEMETRY_DISABLED
609
+ unset LOKI_OTEL_ENDPOINT
610
+ fi
605
611
  TELEMETRY_SCRIPT="$SCRIPT_DIR/telemetry.sh"
606
612
  if [ -f "$TELEMETRY_SCRIPT" ]; then
607
613
  # shellcheck source=telemetry.sh
package/completions/_loki CHANGED
@@ -44,8 +44,11 @@ function _loki {
44
44
  projects)
45
45
  _loki_projects
46
46
  ;;
47
- voice)
48
- _loki_voice
47
+ telemetry)
48
+ _loki_telemetry
49
+ ;;
50
+ agent)
51
+ _loki_agent
49
52
  ;;
50
53
  status)
51
54
  _arguments \
@@ -121,7 +124,8 @@ function _loki_commands {
121
124
  'dogfood:Self-development statistics'
122
125
  'projects:Project registry commands'
123
126
  'enterprise:Enterprise feature commands'
124
- 'voice:Voice input commands'
127
+ 'telemetry:OpenTelemetry management'
128
+ 'agent:Agent type dispatch'
125
129
  'doctor:Check system prerequisites'
126
130
  'onboard:Analyze repo and generate CLAUDE.md'
127
131
  'metrics:Session productivity report'
@@ -294,17 +298,29 @@ function _loki_projects {
294
298
  _describe -t cmds 'projects subcommand' cmds
295
299
  }
296
300
 
297
- function _loki_voice {
301
+ function _loki_telemetry {
302
+ local -a cmds
303
+ cmds=(
304
+ 'status:Show telemetry config'
305
+ 'enable:Enable OTEL'
306
+ 'disable:Disable OTEL for current project'
307
+ 'stop:Permanently opt out across all sessions'
308
+ 'start:Remove persistent opt-out'
309
+ 'help:Telemetry help'
310
+ )
311
+ _describe -t cmds 'telemetry subcommand' cmds
312
+ }
313
+
314
+ function _loki_agent {
298
315
  local -a cmds
299
316
  cmds=(
300
- 'status:Voice input status'
301
- 'listen:Start listening'
302
- 'dictate:Dictate PRD'
303
- 'speak:Text-to-speech'
304
- 'start:Start voice session'
305
- 'help:Voice help'
317
+ 'list:List agent types'
318
+ 'info:Show agent type details'
319
+ 'run:Run agent with prompt'
320
+ 'start:Start agent in background'
321
+ 'help:Agent help'
306
322
  )
307
- _describe -t cmds 'voice subcommand' cmds
323
+ _describe -t cmds 'agent subcommand' cmds
308
324
  }
309
325
 
310
326
  function _loki_reset {
@@ -5,7 +5,7 @@ _loki_completion() {
5
5
  _init_completion || return
6
6
 
7
7
  # Main subcommands (must match autonomy/loki main case statement)
8
- local main_commands="start quick demo init stop pause resume status dashboard logs serve api sandbox notify import github issue config provider reset memory compound checkpoint council dogfood projects enterprise voice secrets doctor watchdog audit metrics syslog onboard share explain plan report test ci watch version completions help"
8
+ local main_commands="start quick demo init stop pause resume status dashboard logs serve api sandbox notify import github issue config provider reset memory compound checkpoint council dogfood projects enterprise secrets doctor watchdog audit metrics syslog onboard share explain plan report test ci watch telemetry agent version completions help"
9
9
 
10
10
  # 1. If we are on the first argument (subcommand)
11
11
  if [[ $cword -eq 1 ]]; then
@@ -83,9 +83,14 @@ _loki_completion() {
83
83
  COMPREPLY=( $(compgen -W "${projects_cmds}" -- "$cur") )
84
84
  ;;
85
85
 
86
- voice)
87
- local voice_cmds="status listen dictate speak start help"
88
- COMPREPLY=( $(compgen -W "${voice_cmds}" -- "$cur") )
86
+ telemetry)
87
+ local telemetry_cmds="status enable disable stop start help"
88
+ COMPREPLY=( $(compgen -W "${telemetry_cmds}" -- "$cur") )
89
+ ;;
90
+
91
+ agent)
92
+ local agent_cmds="list info run start help"
93
+ COMPREPLY=( $(compgen -W "${agent_cmds}" -- "$cur") )
89
94
  ;;
90
95
 
91
96
  syslog)
@@ -7,7 +7,7 @@ Modules:
7
7
  control: Session control API (start/stop/pause/resume)
8
8
  """
9
9
 
10
- __version__ = "6.37.6"
10
+ __version__ = "6.37.8"
11
11
 
12
12
  # Expose the control app for easy import
13
13
  try:
@@ -162,6 +162,7 @@ class ProjectCreate(BaseModel):
162
162
  name: str = Field(..., min_length=1, max_length=255)
163
163
  description: Optional[str] = None
164
164
  prd_path: Optional[str] = None
165
+ tenant_id: int = Field(..., gt=0, description="Tenant ID (required, must be positive)")
165
166
 
166
167
  @field_validator("name")
167
168
  @classmethod
@@ -778,6 +779,7 @@ async def create_project(
778
779
  name=project.name,
779
780
  description=project.description,
780
781
  prd_path=project.prd_path,
782
+ tenant_id=project.tenant_id,
781
783
  )
782
784
  db.add(db_project)
783
785
  await db.flush()
@@ -2662,10 +2664,43 @@ async def pause_session():
2662
2664
  """Pause the current session by creating PAUSE file."""
2663
2665
  if not _control_limiter.check("control"):
2664
2666
  raise HTTPException(status_code=429, detail="Rate limit exceeded")
2665
- pause_file = _get_loki_dir() / "PAUSE"
2667
+
2668
+ loki_dir = _get_loki_dir()
2669
+ pid_file = loki_dir / "loki.pid"
2670
+
2671
+ # Verify loki process is running before attempting pause
2672
+ process_running = False
2673
+ if pid_file.exists():
2674
+ try:
2675
+ pid = int(pid_file.read_text().strip())
2676
+ os.kill(pid, 0) # Signal 0: check existence without killing
2677
+ process_running = True
2678
+ except (ValueError, OSError, ProcessLookupError):
2679
+ pass
2680
+
2681
+ pause_file = loki_dir / "PAUSE"
2666
2682
  pause_file.parent.mkdir(parents=True, exist_ok=True)
2667
2683
  pause_file.write_text(datetime.now(timezone.utc).isoformat())
2668
- return {"success": True, "message": "Session paused"}
2684
+
2685
+ if not process_running:
2686
+ return JSONResponse(
2687
+ status_code=503,
2688
+ content={"success": False, "message": "Session process is not running; pause signal may have no effect"},
2689
+ )
2690
+
2691
+ # Poll up to 5s to confirm process is still alive with PAUSE file present
2692
+ for _ in range(10):
2693
+ try:
2694
+ os.kill(pid, 0)
2695
+ return {"success": True, "message": "Session paused", "process_verified": True}
2696
+ except OSError:
2697
+ break
2698
+ await asyncio.sleep(0.5)
2699
+
2700
+ return JSONResponse(
2701
+ status_code=503,
2702
+ content={"success": False, "message": "Session process exited unexpectedly after pause signal"},
2703
+ )
2669
2704
 
2670
2705
 
2671
2706
  @app.post("/api/control/resume", dependencies=[Depends(auth.require_scope("control"))])
@@ -2673,13 +2708,58 @@ async def resume_session():
2673
2708
  """Resume a paused session by removing PAUSE/STOP files."""
2674
2709
  if not _control_limiter.check("control"):
2675
2710
  raise HTTPException(status_code=429, detail="Rate limit exceeded")
2711
+
2712
+ loki_dir = _get_loki_dir()
2713
+ pid_file = loki_dir / "loki.pid"
2714
+
2715
+ # Verify loki process is running before attempting resume
2716
+ process_running = False
2717
+ pid = 0
2718
+ if pid_file.exists():
2719
+ try:
2720
+ pid = int(pid_file.read_text().strip())
2721
+ os.kill(pid, 0) # Signal 0: check existence without killing
2722
+ process_running = True
2723
+ except (ValueError, OSError, ProcessLookupError):
2724
+ pass
2725
+
2726
+ if not process_running:
2727
+ # Still remove the files for cleanup, but return 503
2728
+ for fname in ["PAUSE", "STOP"]:
2729
+ fpath = loki_dir / fname
2730
+ try:
2731
+ fpath.unlink(missing_ok=True)
2732
+ except Exception:
2733
+ pass
2734
+ return JSONResponse(
2735
+ status_code=503,
2736
+ content={"success": False, "message": "Session did not respond to resume signal"},
2737
+ )
2738
+
2676
2739
  for fname in ["PAUSE", "STOP"]:
2677
- fpath = _get_loki_dir() / fname
2740
+ fpath = loki_dir / fname
2678
2741
  try:
2679
2742
  fpath.unlink(missing_ok=True)
2680
2743
  except Exception:
2681
2744
  pass
2682
- return {"success": True, "message": "Session resumed"}
2745
+
2746
+ # Poll up to 5s to verify the process is still running and acknowledged the resume
2747
+ for _ in range(10):
2748
+ try:
2749
+ os.kill(pid, 0)
2750
+ if not (loki_dir / "PAUSE").exists():
2751
+ return {"success": True, "message": "Session resumed", "process_verified": True}
2752
+ except OSError:
2753
+ return JSONResponse(
2754
+ status_code=503,
2755
+ content={"success": False, "message": "Session did not respond to resume signal"},
2756
+ )
2757
+ await asyncio.sleep(0.5)
2758
+
2759
+ return JSONResponse(
2760
+ status_code=503,
2761
+ content={"success": False, "message": "Session did not respond to resume signal"},
2762
+ )
2683
2763
 
2684
2764
 
2685
2765
  @app.post("/api/control/stop", dependencies=[Depends(auth.require_scope("control"))])
@@ -2774,7 +2854,7 @@ def _calculate_model_cost(model: str, input_tokens: int, output_tokens: int) ->
2774
2854
  pricing = pricing_table.get(model.lower(), pricing_table.get("sonnet", {}))
2775
2855
  input_cost = (input_tokens / 1_000_000) * pricing.get("input", 3.00)
2776
2856
  output_cost = (output_tokens / 1_000_000) * pricing.get("output", 15.00)
2777
- return input_cost + output_cost
2857
+ return round(input_cost + output_cost, 4)
2778
2858
 
2779
2859
 
2780
2860
  @app.get("/api/cost")
@@ -2868,7 +2948,11 @@ async def get_cost():
2868
2948
  "total_input_tokens": total_input,
2869
2949
  "total_output_tokens": total_output,
2870
2950
  "estimated_cost_usd": round(estimated_cost, 4),
2871
- "by_phase": by_phase,
2951
+ "by_phase": {k: {
2952
+ "input_tokens": v["input_tokens"],
2953
+ "output_tokens": v["output_tokens"],
2954
+ "cost_usd": round(v["cost_usd"], 4),
2955
+ } for k, v in by_phase.items()},
2872
2956
  "by_model": {k: {
2873
2957
  "input_tokens": v["input_tokens"],
2874
2958
  "output_tokens": v["output_tokens"],
@@ -2,7 +2,7 @@
2
2
 
3
3
  The flagship product of [Autonomi](https://www.autonomi.dev/). Complete installation instructions for all platforms and use cases.
4
4
 
5
- **Version:** v6.37.6
5
+ **Version:** v6.37.8
6
6
 
7
7
  ---
8
8
 
package/mcp/__init__.py CHANGED
@@ -57,4 +57,4 @@ try:
57
57
  except ImportError:
58
58
  __all__ = ['mcp']
59
59
 
60
- __version__ = '6.37.6'
60
+ __version__ = '6.37.8'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loki-mode",
3
- "version": "6.37.6",
3
+ "version": "6.37.8",
4
4
  "description": "Loki Mode by Autonomi - Multi-agent autonomous startup system for Claude Code, Codex CLI, and Gemini CLI",
5
5
  "keywords": [
6
6
  "agent",
@@ -62,5 +62,5 @@ Describe your project here...
62
62
 
63
63
  - Requirement 1
64
64
  - Requirement 2
65
- `)}},[]),Pl=async()=>{if(!(!M.trim()||tt)){Ql(!0),wl(null),ft(!0);try{const _=await ql.planSession(M,ll);wl(_)}catch{wl({complexity:"unknown",cost_estimate:"N/A",iterations:0,phases:[],output_text:"Failed to run loki plan. The CLI may not be available.",returncode:1})}finally{Ql(!1)}}},S=async()=>{if(!(!M.trim()||g||jl)){ft(!1),Ol(!0);try{await f(M,ll,O.trim()||void 0,Al?"quick":void 0)}finally{Ol(!1)}}};return i.jsxs(i.Fragment,{children:[Xl&&i.jsx(z0,{plan:Yl,loading:tt,onConfirm:S,onCancel:()=>ft(!1)}),i.jsxs("div",{className:"glass p-6 flex flex-col",children:[i.jsxs("div",{className:"flex items-center justify-between mb-4",children:[i.jsx("h3",{className:"text-sm font-semibold text-charcoal uppercase tracking-wider",children:"Product Requirements"}),i.jsx("div",{className:"flex items-center gap-2",children:i.jsxs("div",{className:"relative",children:[i.jsx("button",{onClick:()=>F(!al),className:"text-xs font-medium px-3 py-1.5 rounded-xl border border-primary/20 text-primary hover:bg-primary/5 transition-colors",children:L||"Templates"}),al&&i.jsx("div",{className:"absolute right-0 top-full mt-1 w-56 glass-subtle rounded-xl overflow-hidden z-20 shadow-glass",children:i.jsxs("div",{className:"py-1 max-h-64 overflow-y-auto terminal-scroll",children:[gl&&i.jsx("div",{className:"px-3 py-2 text-xs text-warning border-b border-warning/10",children:"Could not load templates from server. Check that the backend is running."}),!gl&&Nl.length===0&&i.jsx("div",{className:"px-3 py-2 text-xs text-slate",children:"Loading..."}),Nl.map(_=>i.jsx("button",{onClick:()=>Vl(_.filename,_.name),className:"w-full text-left px-3 py-2 text-sm text-charcoal hover:bg-primary/5 transition-colors",children:_.name},_.filename))]})})]})})]}),i.jsx("textarea",{value:M,onChange:_=>R(_.target.value),placeholder:"Paste your PRD here, or select a template above to get started...",className:"flex-1 min-h-[280px] w-full bg-white/40 rounded-xl border border-white/30 px-4 py-3 text-sm font-mono text-charcoal placeholder:text-primary-wash resize-none focus:outline-none focus:ring-2 focus:ring-accent-product/20 focus:border-accent-product/30 transition-all",spellCheck:!1}),i.jsxs("div",{className:"mt-3",children:[i.jsx("label",{className:"block text-xs text-slate font-medium mb-1 uppercase tracking-wider",children:"Project Directory"}),i.jsx("input",{type:"text",value:O,onChange:_=>Q(_.target.value),placeholder:"Leave blank to auto-create, or type a path (e.g. /Users/you/my-project)",className:"w-full bg-white/40 rounded-xl border border-white/30 px-4 py-2 text-sm font-mono text-charcoal placeholder:text-primary-wash/70 focus:outline-none focus:ring-2 focus:ring-accent-product/20 focus:border-accent-product/30 transition-all",spellCheck:!1}),i.jsx("p",{className:"text-[10px] text-slate mt-1",children:"Type a path or leave blank to auto-create under ~/purple-lab-projects/"})]}),p&&i.jsx("div",{className:"mt-3 px-3 py-2 rounded-lg bg-danger/10 border border-danger/20 text-danger text-xs font-medium",children:p}),i.jsxs("div",{className:"flex items-center gap-3 mt-4",children:[i.jsxs("button",{onClick:()=>k(!Al),title:"Quick Mode: 3 iterations max, faster builds",className:`flex items-center gap-1.5 px-3 py-1.5 rounded-xl text-xs font-semibold border transition-all ${Al?"bg-accent-product/10 border-accent-product/30 text-accent-product":"border-white/30 text-slate hover:text-charcoal hover:bg-white/20"}`,children:[i.jsx("span",{className:`w-1.5 h-1.5 rounded-full ${Al?"bg-accent-product":"bg-slate/40"}`}),"Quick"]}),i.jsx("div",{className:"flex-1"}),i.jsxs("span",{className:"text-xs text-slate font-mono",children:[M.length.toLocaleString()," chars"]}),i.jsx("button",{onClick:Pl,disabled:!M.trim()||g||tt,className:`px-4 py-2.5 rounded-xl text-sm font-semibold border transition-all ${!M.trim()||g||tt?"border-white/20 text-slate/40 cursor-not-allowed":"border-accent-product/30 text-accent-product hover:bg-accent-product/5"}`,children:tt?"Analyzing...":"Estimate"}),i.jsx("button",{onClick:S,disabled:!M.trim()||g||jl,className:`px-6 py-2.5 rounded-xl text-sm font-semibold transition-all ${!M.trim()||g||jl?"bg-surface/50 text-slate cursor-not-allowed":"bg-accent-product text-white hover:bg-accent-product/90 shadow-glass-subtle"}`,children:jl?"Starting...":g?"Building...":"Start Build"})]})]})]})}const Cn=[{key:"reason",label:"Reason",description:"Analyzing task, planning approach"},{key:"act",label:"Act",description:"Implementing changes, writing code"},{key:"reflect",label:"Reflect",description:"Reviewing output, self-critique"},{key:"verify",label:"Verify",description:"Testing, validation, quality gates"}];function _0(f){const g=f.toLowerCase();return g.includes("reason")||g.includes("plan")?"reason":g.includes("act")||g.includes("implement")||g.includes("code")?"act":g.includes("reflect")||g.includes("review")?"reflect":g.includes("verify")||g.includes("test")||g.includes("check")?"verify":"idle"}function M0({currentPhase:f,iteration:g}){const p=_0(f);return i.jsxs("div",{className:"glass p-6",children:[i.jsxs("div",{className:"flex items-center justify-between mb-4",children:[i.jsx("h3",{className:"text-sm font-semibold text-charcoal uppercase tracking-wider",children:"RARV Cycle"}),i.jsxs("span",{className:"font-mono text-xs text-slate",children:["Iteration ",g]})]}),i.jsx("div",{className:"flex items-center justify-center mb-5",children:i.jsxs("svg",{viewBox:"0 0 120 120",className:"w-28 h-28",children:[Cn.map((o,T)=>{const M=o.key===p,R=p!=="idle"&&Cn.findIndex(q=>q.key===p)>T,L=(T*90-90)*(Math.PI/180),D=60+40*Math.cos(L),N=60+40*Math.sin(L);return i.jsxs("g",{children:[T<Cn.length-1&&i.jsx("line",{x1:D,y1:N,x2:60+40*Math.cos(((T+1)*90-90)*(Math.PI/180)),y2:60+40*Math.sin(((T+1)*90-90)*(Math.PI/180)),stroke:R?"#3D52A0":"#ADBBDA",strokeWidth:R?2:1,strokeDasharray:R?"none":"4 3"}),T===Cn.length-1&&i.jsx("line",{x1:D,y1:N,x2:60+40*Math.cos(-90*(Math.PI/180)),y2:60+40*Math.sin(-90*(Math.PI/180)),stroke:"#ADBBDA",strokeWidth:1,strokeDasharray:"4 3"}),i.jsx("circle",{cx:D,cy:N,r:M?14:10,fill:M?"#3D52A0":R?"#7091E6":"#EDE8F5",stroke:M?"#6C63FF":R?"#3D52A0":"#ADBBDA",strokeWidth:M?3:1.5,className:M?"phase-active":""}),i.jsx("text",{x:D,y:N+(T===0?-20:T===2?24:0),textAnchor:"middle",className:"text-[9px] font-semibold fill-charcoal",dx:T===1?22:T===3?-22:0,children:o.label[0]})]},o.key)}),i.jsx("text",{x:"60",y:"64",textAnchor:"middle",className:"text-lg font-bold font-mono fill-primary",children:g})]})}),i.jsx("div",{className:"space-y-2",children:Cn.map(o=>{const T=o.key===p;return i.jsxs("div",{className:`flex items-center gap-3 px-3 py-2 rounded-xl transition-all duration-200 ${T?"bg-primary/8 border border-primary/20":"opacity-50"}`,children:[i.jsx("div",{className:`w-2.5 h-2.5 rounded-full flex-shrink-0 ${T?"bg-primary phase-active":"bg-surface"}`}),i.jsxs("div",{children:[i.jsx("span",{className:`text-sm font-semibold ${T?"text-primary":"text-slate"}`,children:o.label}),T&&i.jsx("p",{className:"text-xs text-slate mt-0.5",children:o.description})]})]},o.key)})})]})}const Od={architect:"bg-accent-product/10 text-accent-product border-accent-product/20",developer:"bg-primary/10 text-primary border-primary/20",tester:"bg-success/10 text-success border-success/20",reviewer:"bg-warning/10 text-warning border-warning/20",planner:"bg-primary-wash/20 text-charcoal border-primary-wash/30",default:"bg-surface/30 text-slate border-surface/50"};function O0(f){const g=f.toLowerCase();for(const[p,o]of Object.entries(Od))if(g.includes(p))return o;return Od.default}function D0({agents:f,loading:g}){const p=(f==null?void 0:f.filter(T=>T.alive))||[],o=(f==null?void 0:f.filter(T=>!T.alive))||[];return i.jsxs("div",{className:"glass p-6",children:[i.jsxs("div",{className:"flex items-center justify-between mb-4",children:[i.jsx("h3",{className:"text-sm font-semibold text-charcoal uppercase tracking-wider",children:"Agents"}),i.jsxs("span",{className:"font-mono text-xs text-slate",children:[p.length," active"]})]}),g&&!f&&i.jsx("div",{className:"text-center py-8 text-slate text-sm",children:"Loading agents..."}),!g&&(f==null?void 0:f.length)===0&&i.jsxs("div",{className:"text-center py-8",children:[i.jsx("p",{className:"text-slate text-sm",children:"No agents running"}),i.jsx("p",{className:"text-primary-wash text-xs mt-1",children:"Start a build to spawn agents"})]}),p.length>0&&i.jsx("div",{className:"space-y-2 mb-4",children:p.map(T=>i.jsx(Dd,{agent:T},T.id))}),o.length>0&&i.jsxs("details",{className:"mt-3",children:[i.jsxs("summary",{className:"text-xs text-slate cursor-pointer hover:text-charcoal transition-colors",children:[o.length," completed"]}),i.jsx("div",{className:"space-y-1.5 mt-2",children:o.slice(0,10).map(T=>i.jsx(Dd,{agent:T,compact:!0},T.id))})]})]})}function Dd({agent:f,compact:g}){const p=O0(f.type||f.name);return g?i.jsxs("div",{className:"flex items-center gap-2 px-2 py-1 rounded-lg bg-white/30 text-xs",children:[i.jsx("div",{className:"w-1.5 h-1.5 rounded-full bg-slate/30"}),i.jsx("span",{className:"font-medium text-slate truncate",children:f.name||f.id}),i.jsx("span",{className:"text-primary-wash ml-auto",children:f.type})]}):i.jsxs("div",{className:`flex items-start gap-3 px-3 py-2.5 rounded-xl border ${p}`,children:[i.jsx("div",{className:"flex-shrink-0 mt-0.5",children:i.jsx("div",{className:`w-2.5 h-2.5 rounded-full ${f.alive?"bg-success phase-active":"bg-slate/30"}`})}),i.jsxs("div",{className:"flex-1 min-w-0",children:[i.jsxs("div",{className:"flex items-center gap-2",children:[i.jsx("span",{className:"text-sm font-semibold truncate",children:f.name||f.id}),f.type&&i.jsx("span",{className:"text-[10px] font-mono font-medium opacity-70",children:f.type})]}),f.task&&i.jsx("p",{className:"text-xs opacity-70 mt-0.5 truncate",children:f.task}),f.status&&f.status!=="unknown"&&i.jsx("span",{className:"inline-block text-[10px] font-mono mt-1 opacity-60",children:f.status})]}),f.pid&&i.jsxs("span",{className:"text-[10px] font-mono text-slate/50 flex-shrink-0",children:["PID ",f.pid]})]})}const U0={info:"text-primary-light",error:"text-danger",warning:"text-warning",debug:"text-slate",critical:"text-danger font-bold"};function C0(f){if(!f)return"";if(f.includes("T")||f.includes("-"))try{return new Date(f).toLocaleTimeString("en-US",{hour12:!1})}catch{return f}return f}function R0({logs:f,loading:g,subscribe:p}){const o=U.useRef(null),[T,M]=U.useState(!1),[R,L]=U.useState([]);U.useEffect(()=>p?p("log",Q=>{const ll=Q;ll!=null&&ll.line&&L(al=>{const F=[...al,{message:ll.line,timestamp:ll.timestamp||""}];return F.length>500?F.slice(-500):F})}):void 0,[p]);const D=(()=>{const O=R.map(F=>{let Nl="info";const xl=F.message.toLowerCase();return xl.includes("error")||xl.includes("fail")?Nl="error":xl.includes("warn")?Nl="warning":xl.includes("debug")&&(Nl="debug"),{timestamp:F.timestamp,level:Nl,message:F.message,source:"ws"}}),Q=f||[];if(O.length===0)return Q;if(Q.length===0)return O;const ll=new Set(O.map(F=>F.message));return[...Q.filter(F=>!ll.has(F.message)),...O]})();U.useEffect(()=>{!T&&o.current&&(o.current.scrollTop=o.current.scrollHeight)},[D,T]);const N=()=>{if(!o.current)return;const{scrollTop:O,scrollHeight:Q,clientHeight:ll}=o.current,al=Q-O-ll<50;M(!al)},q=()=>{var O;M(!1),(O=o.current)==null||O.scrollTo({top:o.current.scrollHeight,behavior:"smooth"})};return i.jsxs("div",{className:"glass p-0 overflow-hidden flex flex-col h-full",children:[i.jsxs("div",{className:"flex items-center justify-between px-4 py-3 border-b border-white/10",children:[i.jsx("h3",{className:"text-sm font-semibold text-charcoal uppercase tracking-wider",children:"Terminal"}),i.jsxs("div",{className:"flex items-center gap-3",children:[i.jsxs("span",{className:"font-mono text-xs text-slate",children:[D.length," lines"]}),i.jsx("button",{onClick:T?q:()=>M(!0),className:`text-xs font-medium px-2.5 py-1 rounded-lg border transition-colors ${T?"border-warning/40 text-warning bg-warning/5 hover:bg-warning/10":"border-primary/20 text-primary hover:bg-primary/5"}`,title:T?"Scroll locked -- click to resume auto-scroll":"Auto-scrolling -- click to lock",children:T?"Locked":"Live"}),T&&i.jsx("button",{onClick:q,className:"text-xs text-primary hover:text-primary-light transition-colors font-medium",children:"Jump to bottom"})]})]}),i.jsxs("div",{ref:o,onScroll:N,className:"flex-1 overflow-y-auto terminal-scroll bg-charcoal/[0.03] p-4 font-mono text-xs leading-relaxed min-h-[300px]",children:[g&&!f&&R.length===0&&i.jsx("div",{className:"text-slate animate-pulse",children:"Connecting to log stream..."}),D.length===0&&!g&&i.jsxs("div",{className:"text-slate/60",children:[i.jsx("p",{children:"No log output yet."}),i.jsx("p",{className:"mt-1",children:"Start a build to see terminal output here."})]}),D.map((O,Q)=>i.jsxs("div",{className:"flex gap-2 hover:bg-white/5 rounded px-1 -mx-1",children:[i.jsx("span",{className:"text-slate/40 flex-shrink-0 select-none w-16 text-right",children:C0(O.timestamp)}),i.jsx("span",{className:`flex-shrink-0 w-12 text-right uppercase text-[10px] font-semibold ${U0[O.level]||"text-slate"}`,children:O.level}),i.jsx("span",{className:`flex-1 break-all ${O.level==="error"||O.level==="critical"?"text-danger":"text-charcoal/80"}`,children:O.message})]},Q)),D.length>0&&i.jsx("div",{className:"terminal-cursor mt-1"})]})]})}const H0={pass:{badge:"bg-success/10 text-success border-success/20",dot:"bg-success",label:"Pass"},fail:{badge:"bg-danger/10 text-danger border-danger/20",dot:"bg-danger",label:"Fail"},skip:{badge:"bg-slate/10 text-slate border-slate/20",dot:"bg-slate/40",label:"Skip"},pending:{badge:"bg-warning/10 text-warning border-warning/20",dot:"bg-warning",label:"Pending"}};function B0({item:f}){const[g,p]=U.useState(!1),o=H0[f.status];return i.jsxs("div",{className:`border rounded-xl overflow-hidden ${o.badge}`,children:[i.jsxs("button",{type:"button",className:"w-full flex items-center gap-3 px-3 py-2.5 text-left",onClick:()=>f.details&&p(!g),children:[i.jsx("span",{className:`w-2 h-2 rounded-full flex-shrink-0 ${o.dot}`}),i.jsx("span",{className:"text-sm font-medium flex-1 truncate",children:f.label}),i.jsx("span",{className:"text-[10px] font-mono font-semibold uppercase tracking-wider flex-shrink-0",children:o.label}),f.details&&i.jsx("span",{className:"text-xs text-slate/60 flex-shrink-0",children:g?"v":">"})]}),g&&f.details&&i.jsx("div",{className:"px-3 pb-2.5 pt-0",children:i.jsx("p",{className:"text-xs font-mono opacity-70 leading-relaxed",children:f.details})})]})}function q0({checklist:f,loading:g}){const p=f&&f.total>0?f.passed/f.total*100:0;return i.jsxs("div",{className:"glass p-6",children:[i.jsxs("div",{className:"flex items-center justify-between mb-4",children:[i.jsx("h3",{className:"text-sm font-semibold text-charcoal uppercase tracking-wider",children:"Quality Gates"}),f&&i.jsxs("span",{className:"font-mono text-xs text-slate",children:[f.passed,"/",f.total," passed"]})]}),g&&!f&&i.jsx("div",{className:"text-center py-8 text-slate text-sm",children:"Loading gates..."}),!g&&!f&&i.jsxs("div",{className:"text-center py-8",children:[i.jsx("p",{className:"text-slate text-sm",children:"No quality gate data"}),i.jsx("p",{className:"text-primary-wash text-xs mt-1",children:"Gates run during verification phase"})]}),f&&i.jsxs(i.Fragment,{children:[i.jsxs("div",{className:"flex items-center gap-4 mb-3 text-xs",children:[i.jsxs("span",{className:"text-success font-medium",children:[f.passed," passed"]}),f.failed>0&&i.jsxs("span",{className:"text-danger font-medium",children:[f.failed," failed"]}),f.skipped>0&&i.jsxs("span",{className:"text-slate",children:[f.skipped," skipped"]}),f.pending>0&&i.jsxs("span",{className:"text-warning",children:[f.pending," pending"]})]}),i.jsx("div",{className:"w-full h-2 bg-charcoal/10 rounded-full overflow-hidden mb-4",children:i.jsx("div",{className:"h-full bg-success rounded-full transition-all duration-500",style:{width:`${p}%`}})}),i.jsx("div",{className:"space-y-2 max-h-[400px] overflow-y-auto terminal-scroll",children:f.items.map(o=>i.jsx(B0,{item:o},o.id))})]})]})}const Y0={".py":"bg-success",".ts":"bg-primary",".tsx":"bg-primary",".md":"bg-warning",".sh":"bg-accent-product"};function G0(f){const g=f.substring(f.lastIndexOf("."));return Y0[g]||"bg-slate"}function w0(f){return f==null?"":f<1024?`${f}B`:f<1024*1024?`${(f/1024).toFixed(1)}KB`:`${(f/(1024*1024)).toFixed(1)}MB`}function Hd({node:f,depth:g,onSelectFile:p,selectedPath:o}){const[T,M]=U.useState(g===0),R=f.type==="directory",L=f.path===o;return i.jsxs("div",{children:[i.jsxs("button",{type:"button",className:`w-full flex items-center gap-2 px-2 py-1 rounded-lg text-left text-sm transition-colors hover:bg-white/30 ${L?"bg-primary/10 text-primary":"text-charcoal"}`,style:{paddingLeft:`${g*16+8}px`},onClick:()=>{R?M(!T):p(f.path)},children:[R?i.jsx("span",{className:"font-mono text-xs text-slate w-3 flex-shrink-0",children:T?"v":">"}):i.jsx("span",{className:`w-2 h-2 rounded-full flex-shrink-0 ${G0(f.name)}`}),i.jsx("span",{className:`truncate ${R?"font-medium":"font-mono text-xs"}`,children:f.name}),!R&&f.size!==void 0&&i.jsx("span",{className:"ml-auto text-[10px] font-mono text-slate/60 flex-shrink-0",children:w0(f.size)})]}),R&&T&&f.children&&i.jsx("div",{children:f.children.map(D=>i.jsx(Hd,{node:D,depth:g+1,onSelectFile:p,selectedPath:o},D.path))})]})}function Q0({files:f,loading:g}){const[p,o]=U.useState(null),[T,M]=U.useState(null),[R,L]=U.useState(!1),[D,N]=U.useState(null),q=U.useCallback(async Q=>{M(null),o(Q),L(!0),N(null);try{const ll=await ql.getFileContent(Q);M(ll.content)}catch(ll){const al=ll instanceof Error?ll.message:"Unknown error",F=ll instanceof TypeError||al==="Request timeout",Nl=al.includes("404")||al.includes("not found")||al.includes("Not found");N(F?"Network error - server may be unreachable":Nl?"File not found - it may have been deleted or renamed":al),M(null)}finally{L(!1)}},[]),O=U.useCallback(Q=>{q(Q)},[q]);return i.jsxs("div",{className:"glass p-6 flex flex-col",style:{minHeight:"300px"},children:[i.jsxs("div",{className:"flex items-center justify-between mb-4",children:[i.jsx("h3",{className:"text-sm font-semibold text-charcoal uppercase tracking-wider",children:"File Browser"}),i.jsx("span",{className:"font-mono text-xs text-slate",children:".loki/"})]}),g&&!f&&i.jsx("div",{className:"text-center py-8 text-slate text-sm",children:"Loading files..."}),!g&&(!f||f.length===0)&&i.jsxs("div",{className:"text-center py-8",children:[i.jsx("p",{className:"text-slate text-sm",children:"No project files found"}),i.jsx("p",{className:"text-primary-wash text-xs mt-1",children:"Start a session to generate .loki/ state"})]}),f&&f.length>0&&i.jsxs("div",{className:"flex gap-4 flex-1 min-h-0",children:[i.jsx("div",{className:"w-1/2 overflow-y-auto terminal-scroll pr-2",children:f.map(Q=>i.jsx(Hd,{node:Q,depth:0,onSelectFile:O,selectedPath:p},Q.path))}),i.jsxs("div",{className:"w-1/2 bg-charcoal/5 rounded-xl p-3 overflow-hidden flex flex-col",children:[!p&&i.jsx("div",{className:"flex-1 flex items-center justify-center text-slate text-xs",children:"Select a file to preview"}),p&&i.jsxs(i.Fragment,{children:[i.jsx("div",{className:"text-xs font-mono text-primary mb-2 truncate",children:p}),i.jsx("div",{className:"flex-1 overflow-y-auto terminal-scroll",children:R?i.jsx("div",{className:"text-slate text-xs",children:"Loading..."}):D?i.jsxs("div",{className:"flex flex-col items-center justify-center gap-2 py-6",children:[i.jsx("p",{className:"text-danger text-xs font-medium",children:"Failed to load file"}),i.jsx("p",{className:"text-slate text-[10px] text-center max-w-[200px] break-words",children:D}),i.jsx("button",{type:"button",onClick:()=>p&&q(p),className:"mt-1 px-3 py-1 text-[10px] font-semibold rounded-lg border border-primary/20 text-primary hover:bg-primary/5 transition-colors",children:"Retry"})]}):i.jsx("pre",{className:"text-xs font-mono text-charcoal whitespace-pre-wrap break-words leading-relaxed",children:T})})]})]})]})]})}const Ud=5e5;function Cd(f){return f>=1e6?`${(f/1e6).toFixed(1)}M`:f>=1e3?`${(f/1e3).toFixed(1)}K`:f.toString()}function X0(f){if(!f)return"Never";try{const g=new Date(f),o=new Date().getTime()-g.getTime(),T=Math.floor(o/(1e3*60*60));return T<1?"Just now":T<24?`${T}h ago`:`${Math.floor(T/24)}d ago`}catch{return f}}function L0({memory:f,loading:g}){const p=f?[{label:"Episodic",count:f.episodic_count,color:"text-primary",bg:"bg-primary/10",border:"border-primary/20"},{label:"Semantic",count:f.semantic_count,color:"text-success",bg:"bg-success/10",border:"border-success/20"},{label:"Skills",count:f.skill_count,color:"text-warning",bg:"bg-warning/10",border:"border-warning/20"}]:[],o=f?Math.min(f.total_tokens/Ud*100,100):0;return i.jsxs("div",{className:"glass p-6",children:[i.jsxs("div",{className:"flex items-center justify-between mb-4",children:[i.jsx("h3",{className:"text-sm font-semibold text-charcoal uppercase tracking-wider",children:"Memory System"}),f&&i.jsx("span",{className:"font-mono text-xs text-slate",children:X0(f.last_consolidation)})]}),g&&!f&&i.jsx("div",{className:"text-center py-8 text-slate text-sm",children:"Loading memory..."}),!g&&!f&&i.jsxs("div",{className:"text-center py-8",children:[i.jsx("p",{className:"text-slate text-sm",children:"No memory data available"}),i.jsx("p",{className:"text-primary-wash text-xs mt-1",children:"Memory populates during autonomous runs"})]}),f&&i.jsxs(i.Fragment,{children:[i.jsx("div",{className:"grid grid-cols-3 gap-3 mb-4",children:p.map(T=>i.jsxs("div",{className:`${T.bg} border ${T.border} rounded-xl p-3 text-center`,children:[i.jsx("div",{className:`text-2xl font-bold font-mono ${T.color}`,children:T.count}),i.jsx("div",{className:"text-[10px] text-slate font-medium mt-1 uppercase tracking-wider",children:T.label})]},T.label))}),i.jsxs("div",{className:"mt-3",children:[i.jsxs("div",{className:"flex items-center justify-between mb-1.5",children:[i.jsx("span",{className:"text-xs text-slate font-medium",children:"Token Usage"}),i.jsxs("span",{className:"text-xs font-mono text-charcoal",children:[Cd(f.total_tokens)," / ",Cd(Ud)]})]}),i.jsx("div",{className:"w-full h-2 bg-charcoal/10 rounded-full overflow-hidden",children:i.jsx("div",{className:`h-full rounded-full transition-all duration-500 ${o>80?"bg-danger":o>50?"bg-warning":"bg-primary-light"}`,style:{width:`${o}%`}})})]}),i.jsxs("div",{className:"mt-3 flex items-center justify-between text-xs",children:[i.jsx("span",{className:"text-slate",children:"Last Consolidation"}),i.jsx("span",{className:"font-mono text-charcoal",children:f.last_consolidation?new Date(f.last_consolidation).toLocaleString():"Never"})]})]})]})}function Z0({visible:f}){const[g,p]=U.useState("markdown"),[o,T]=U.useState(null),[M,R]=U.useState(null),[L,D]=U.useState(!1),[N,q]=U.useState(!1),[O,Q]=U.useState(null),[ll,al]=U.useState(!1);if(!f)return null;const F=async()=>{D(!0),Q(null),T(null),R(null);try{const J=await ql.generateReport(g);T(J)}catch(J){Q(J instanceof Error?J.message:"Failed to generate report")}finally{D(!1)}},Nl=async()=>{q(!0),Q(null);try{const J=await ql.shareSession();R(J)}catch(J){Q(J instanceof Error?J.message:"Failed to share session")}finally{q(!1)}},xl=async J=>{try{await navigator.clipboard.writeText(J),al(!0),setTimeout(()=>al(!1),2e3)}catch{}},gl=()=>{if(!o)return;const J=new Blob([o.content],{type:g==="html"?"text/html":"text/markdown"}),jl=URL.createObjectURL(J),Ol=document.createElement("a");Ol.href=jl,Ol.download=`loki-report.${g==="html"?"html":"md"}`,Ol.click(),URL.revokeObjectURL(jl)};return i.jsxs("div",{className:"glass p-4 rounded-2xl",children:[i.jsxs("div",{className:"flex items-center justify-between mb-3",children:[i.jsx("h3",{className:"text-sm font-semibold text-charcoal uppercase tracking-wider",children:"Session Report"}),i.jsxs("div",{className:"flex items-center gap-2",children:[i.jsx("div",{className:"flex items-center gap-1 glass-subtle rounded-xl p-1",children:["markdown","html"].map(J=>i.jsx("button",{onClick:()=>p(J),className:`px-3 py-1 text-xs font-semibold rounded-lg transition-all ${g===J?"bg-accent-product text-white shadow-sm":"text-slate hover:text-charcoal hover:bg-white/40"}`,children:J.toUpperCase()},J))}),i.jsx("button",{onClick:F,disabled:L,className:"px-4 py-1.5 rounded-xl text-xs font-semibold bg-accent-product text-white hover:bg-accent-product/90 disabled:opacity-50 transition-all",children:L?"Generating...":"Generate Report"})]})]}),O&&i.jsx("div",{className:"mb-3 px-3 py-2 rounded-lg bg-danger/10 border border-danger/20 text-danger text-xs",children:O}),o&&i.jsxs("div",{className:"mt-3",children:[i.jsxs("div",{className:"flex items-center gap-2 mb-2",children:[i.jsxs("span",{className:"text-xs text-slate",children:["Report generated (",o.format,")"]}),i.jsx("div",{className:"flex-1"}),i.jsx("button",{onClick:()=>xl(o.content),className:"px-3 py-1 text-xs font-medium text-slate hover:text-charcoal border border-white/30 rounded-lg hover:bg-white/30 transition-all",children:ll?"Copied":"Copy"}),i.jsx("button",{onClick:gl,className:"px-3 py-1 text-xs font-medium text-slate hover:text-charcoal border border-white/30 rounded-lg hover:bg-white/30 transition-all",children:"Download"}),i.jsx("button",{onClick:Nl,disabled:N,className:"px-3 py-1 text-xs font-medium bg-accent-product/10 text-accent-product border border-accent-product/20 rounded-lg hover:bg-accent-product/20 disabled:opacity-50 transition-all",children:N?"Sharing...":"Share as Gist"})]}),M&&i.jsxs("div",{className:"mb-2 flex items-center gap-2 px-3 py-2 rounded-lg bg-success/10 border border-success/20",children:[i.jsx("span",{className:"text-xs text-success font-medium",children:"Shared:"}),M.url?i.jsx("a",{href:M.url,target:"_blank",rel:"noopener noreferrer",className:"text-xs text-accent-product underline flex-1 truncate",children:M.url}):i.jsx("span",{className:"text-xs text-slate flex-1",children:"No URL returned"}),M.url&&i.jsx("button",{onClick:()=>xl(M.url),className:"text-xs text-slate hover:text-charcoal",children:"Copy URL"})]}),i.jsx("pre",{className:"text-[11px] font-mono text-charcoal bg-black/5 rounded-xl p-3 overflow-auto max-h-64 whitespace-pre-wrap terminal-scroll",children:o.content||"(empty report)"})]})]})}function Rd({visible:f}){const g=U.useCallback(()=>ql.getMetrics(),[]),{data:p,loading:o}=Ra(g,15e3,f);return f?i.jsxs("div",{className:"glass p-4 rounded-2xl",children:[i.jsxs("div",{className:"flex items-center justify-between mb-3",children:[i.jsx("h3",{className:"text-sm font-semibold text-charcoal uppercase tracking-wider",children:"Session Metrics"}),o&&i.jsx("div",{className:"w-4 h-4 border-2 border-accent-product border-t-transparent rounded-full animate-spin"})]}),p?i.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[i.jsxs("div",{className:"glass-subtle rounded-xl p-3",children:[i.jsx("div",{className:"text-[10px] font-semibold text-slate uppercase tracking-wider mb-1",children:"Iterations"}),i.jsx("div",{className:"text-xl font-bold text-charcoal",children:p.iterations??0})]}),i.jsxs("div",{className:"glass-subtle rounded-xl p-3",children:[i.jsx("div",{className:"text-[10px] font-semibold text-slate uppercase tracking-wider mb-1",children:"Gate Pass Rate"}),i.jsx("div",{className:"text-xl font-bold text-charcoal",children:typeof p.quality_gate_pass_rate=="number"?`${p.quality_gate_pass_rate.toFixed(0)}%`:"N/A"})]}),i.jsxs("div",{className:"glass-subtle rounded-xl p-3",children:[i.jsx("div",{className:"text-[10px] font-semibold text-slate uppercase tracking-wider mb-1",children:"Tokens Used"}),i.jsx("div",{className:"text-xl font-bold text-charcoal",children:(p.tokens_used??0).toLocaleString()})]}),i.jsxs("div",{className:"glass-subtle rounded-xl p-3",children:[i.jsx("div",{className:"text-[10px] font-semibold text-slate uppercase tracking-wider mb-1",children:"Time Elapsed"}),i.jsx("div",{className:"text-xl font-bold text-charcoal",children:p.time_elapsed||"N/A"})]})]}):i.jsx("div",{className:"text-sm text-slate py-4 text-center",children:o?"Loading metrics...":"No metrics available"})]}):null}const V0={completed:{bg:"bg-success/10",text:"text-success",label:"Completed"},complete:{bg:"bg-success/10",text:"text-success",label:"Completed"},done:{bg:"bg-success/10",text:"text-success",label:"Completed"},in_progress:{bg:"bg-primary/10",text:"text-primary",label:"In Progress"},started:{bg:"bg-warning/10",text:"text-warning",label:"Started"},error:{bg:"bg-danger/10",text:"text-danger",label:"Failed"},failed:{bg:"bg-danger/10",text:"text-danger",label:"Failed"},empty:{bg:"bg-slate/10",text:"text-slate",label:"Empty"}};function K0(f){return V0[f]||{bg:"bg-slate/10",text:"text-slate",label:f}}function J0({onLoadSession:f}){const g=U.useCallback(()=>ql.getSessionsHistory(),[]),{data:p,loading:o}=Ra(g,6e4,!0);return o&&!p?i.jsxs("div",{className:"glass p-4 rounded-2xl",children:[i.jsx("h3",{className:"text-sm font-semibold text-charcoal uppercase tracking-wider mb-3",children:"Past Builds"}),i.jsx("div",{className:"text-sm text-slate",children:"Loading..."})]}):!p||p.length===0?null:i.jsxs("div",{className:"glass p-4 rounded-2xl",children:[i.jsx("h3",{className:"text-sm font-semibold text-charcoal uppercase tracking-wider mb-3",children:"Past Builds"}),i.jsx("div",{className:"flex flex-col gap-2 max-h-64 overflow-y-auto terminal-scroll",children:p.map(T=>{const M=K0(T.status),R=T.file_count;return i.jsxs("button",{onClick:()=>f==null?void 0:f(T),className:"text-left px-4 py-3 rounded-xl glass-subtle hover:bg-white/40 transition-all group cursor-pointer",children:[i.jsxs("div",{className:"flex items-center justify-between mb-1",children:[i.jsx("span",{className:"text-[10px] font-mono text-slate",children:T.date}),i.jsxs("div",{className:"flex items-center gap-2",children:[R!==void 0&&R>0&&i.jsxs("span",{className:"text-[10px] font-mono text-slate",children:[R," files"]}),i.jsx("span",{className:`text-[10px] font-semibold px-2 py-0.5 rounded-full ${M.bg} ${M.text}`,children:M.label})]})]}),i.jsx("div",{className:"text-xs text-charcoal truncate group-hover:text-accent-product transition-colors",children:T.prd_snippet||T.id}),i.jsx("div",{className:"text-[10px] font-mono text-slate/60 mt-0.5 truncate",children:T.path})]},T.id)})})]})}function k0(){const[f,g]=U.useState(null),[p,o]=U.useState(!1),[T,M]=U.useState(!1),[R,L]=U.useState(null),[D,N]=U.useState(!1),[q,O]=U.useState(!1),[Q,ll]=U.useState(!1),[al,F]=U.useState("terminal"),[Nl,xl]=U.useState("claude"),[gl,J]=U.useState(null),[jl,Ol]=U.useState(null),[Al,k]=U.useState(null),[Yl,wl]=U.useState(null),tt=U.useCallback(pl=>{if(!pl){Ol(null),k(null),wl(null);return}Ol(pl.status),k(pl.agents),wl(pl.logs),o(pl.status.running??!1),M(pl.status.paused??!1)},[]),{connected:Ql,subscribe:Xl}=p0(tt),ft=U.useCallback(()=>ql.getStatus(),[]),{data:Vl}=Ra(ft,3e4,!Ql);U.useEffect(()=>{jl===null&&Vl!==null&&(o(Vl.running??!1),M(Vl.paused??!1))},[Vl,jl]),U.useEffect(()=>{p&&N(!0)},[p]);const Pl=U.useCallback(()=>ql.getMemorySummary(),[]),S=U.useCallback(()=>ql.getChecklist(),[]),_=U.useCallback(()=>ql.getFiles(),[]),{data:G,loading:ul}=Ra(Pl,3e4,p),{data:ol,loading:m}=Ra(S,3e4,p),{data:A,loading:C}=Ra(_,3e4,p),H=jl??Vl,Z=Al,W=Yl,cl=Al===null,Kl=Yl===null,El=U.useCallback(async(pl,Yt,Hn,Ba)=>{g(null),N(!1),O(!1),F("terminal");try{await ql.startSession({prd:pl,provider:Yt,projectDir:Hn,mode:Ba}),L(pl)}catch($e){g($e instanceof Error?$e.message:"Failed to start session")}},[]),_e=U.useCallback(async()=>{try{(await ql.stopSession()).stopped&&(o(!1),M(!1),L(null),Ol(null),k(null),wl(null))}catch{o(!1),M(!1),L(null)}},[]),Je=U.useCallback(async pl=>{try{const Yt=await ql.getSessionDetail(pl.id);J(Yt)}catch{}},[]),ke=U.useCallback(pl=>{xl(pl)},[]),Rn=U.useCallback(async()=>{try{await ql.pauseSession(),M(!0)}catch{}},[]),qt=U.useCallback(async()=>{try{await ql.resumeSession(),M(!1)}catch{}},[]),Ha=R&&R.replace(/^#+\s*/gm,"").split(`
65
+ `)}},[]),Pl=async()=>{if(!(!M.trim()||tt)){Ql(!0),wl(null),ft(!0);try{const _=await ql.planSession(M,ll);wl(_)}catch{wl({complexity:"unknown",cost_estimate:"N/A",iterations:0,phases:[],output_text:"Failed to run loki plan. The CLI may not be available.",returncode:1})}finally{Ql(!1)}}},S=async()=>{if(!(!M.trim()||g||jl)){ft(!1),Ol(!0);try{await f(M,ll,O.trim()||void 0,Al?"quick":void 0)}finally{Ol(!1)}}};return i.jsxs(i.Fragment,{children:[Xl&&i.jsx(z0,{plan:Yl,loading:tt,onConfirm:S,onCancel:()=>ft(!1)}),i.jsxs("div",{className:"glass p-6 flex flex-col",children:[i.jsxs("div",{className:"flex items-center justify-between mb-4",children:[i.jsx("h3",{className:"text-sm font-semibold text-charcoal uppercase tracking-wider",children:"Product Requirements"}),i.jsx("div",{className:"flex items-center gap-2",children:i.jsxs("div",{className:"relative",children:[i.jsx("button",{onClick:()=>F(!al),className:"text-xs font-medium px-3 py-1.5 rounded-xl border border-primary/20 text-primary hover:bg-primary/5 transition-colors",children:L||"Templates"}),al&&i.jsx("div",{className:"absolute right-0 top-full mt-1 w-56 glass-subtle rounded-xl overflow-hidden z-20 shadow-glass",children:i.jsxs("div",{className:"py-1 max-h-64 overflow-y-auto terminal-scroll",children:[gl&&i.jsx("div",{className:"px-3 py-2 text-xs text-warning border-b border-warning/10",children:"Could not load templates from server. Check that the backend is running."}),!gl&&Nl.length===0&&i.jsx("div",{className:"px-3 py-2 text-xs text-slate",children:"Loading..."}),Nl.map(_=>i.jsx("button",{onClick:()=>Vl(_.filename,_.name),className:"w-full text-left px-3 py-2 text-sm text-charcoal hover:bg-primary/5 transition-colors",children:_.name},_.filename))]})})]})})]}),i.jsx("textarea",{value:M,onChange:_=>R(_.target.value),placeholder:"Paste your PRD here, or select a template above to get started...",className:"flex-1 min-h-[280px] w-full bg-white/40 rounded-xl border border-white/30 px-4 py-3 text-sm font-mono text-charcoal placeholder:text-primary-wash resize-none focus:outline-none focus:ring-2 focus:ring-accent-product/20 focus:border-accent-product/30 transition-all",spellCheck:!1}),i.jsxs("div",{className:"mt-3",children:[i.jsx("label",{className:"block text-xs text-slate font-medium mb-1 uppercase tracking-wider",children:"Project Directory"}),i.jsx("input",{type:"text",value:O,onChange:_=>Q(_.target.value),placeholder:"Leave blank to auto-create, or type a path (e.g. /Users/you/my-project)",className:"w-full bg-white/40 rounded-xl border border-white/30 px-4 py-2 text-sm font-mono text-charcoal placeholder:text-primary-wash/70 focus:outline-none focus:ring-2 focus:ring-accent-product/20 focus:border-accent-product/30 transition-all",spellCheck:!1}),i.jsx("p",{className:"text-[10px] text-slate mt-1",children:"Type a path or leave blank to auto-create under ~/purple-lab-projects/"})]}),p&&i.jsx("div",{className:"mt-3 px-3 py-2 rounded-lg bg-danger/10 border border-danger/20 text-danger text-xs font-medium",children:p}),i.jsxs("div",{className:"flex items-center gap-3 mt-4",children:[i.jsxs("button",{onClick:()=>k(!Al),title:"Quick Mode: 3 iterations max, faster builds",className:`flex items-center gap-1.5 px-3 py-1.5 rounded-xl text-xs font-semibold border transition-all ${Al?"bg-accent-product/10 border-accent-product/30 text-accent-product":"border-white/30 text-slate hover:text-charcoal hover:bg-white/20"}`,children:[i.jsx("span",{className:`w-1.5 h-1.5 rounded-full ${Al?"bg-accent-product":"bg-slate/40"}`}),"Quick"]}),i.jsx("div",{className:"flex-1"}),i.jsxs("span",{className:"text-xs text-slate font-mono",children:[M.length.toLocaleString()," chars"]}),i.jsx("button",{onClick:Pl,disabled:!M.trim()||g||tt,className:`px-4 py-2.5 rounded-xl text-sm font-semibold border transition-all ${!M.trim()||g||tt?"border-white/20 text-slate/40 cursor-not-allowed":"border-accent-product/30 text-accent-product hover:bg-accent-product/5"}`,children:tt?"Analyzing...":"Estimate"}),i.jsx("button",{onClick:S,disabled:!M.trim()||g||jl,className:`px-6 py-2.5 rounded-xl text-sm font-semibold transition-all ${!M.trim()||g||jl?"bg-surface/50 text-slate cursor-not-allowed":"bg-accent-product text-white hover:bg-accent-product/90 shadow-glass-subtle"}`,children:jl?"Starting...":g?"Building...":"Start Build"})]})]})]})}const Cn=[{key:"reason",label:"Reason",description:"Analyzing task, planning approach"},{key:"act",label:"Act",description:"Implementing changes, writing code"},{key:"reflect",label:"Reflect",description:"Reviewing output, self-critique"},{key:"verify",label:"Verify",description:"Testing, validation, quality gates"}];function _0(f){const g=f.toLowerCase();return g.includes("reason")||g.includes("plan")?"reason":g.includes("act")||g.includes("implement")||g.includes("code")?"act":g.includes("reflect")||g.includes("review")?"reflect":g.includes("verify")||g.includes("test")||g.includes("check")?"verify":"idle"}function M0({currentPhase:f,iteration:g}){const p=_0(f);return i.jsxs("div",{className:"glass p-6",children:[i.jsxs("div",{className:"flex items-center justify-between mb-4",children:[i.jsx("h3",{className:"text-sm font-semibold text-charcoal uppercase tracking-wider",children:"RARV Cycle"}),i.jsxs("span",{className:"font-mono text-xs text-slate",children:["Iteration ",g]})]}),i.jsx("div",{className:"flex items-center justify-center mb-5",children:i.jsxs("svg",{viewBox:"0 0 120 120",className:"w-28 h-28",children:[Cn.map((o,T)=>{const M=o.key===p,R=p!=="idle"&&Cn.findIndex(q=>q.key===p)>T,L=(T*90-90)*(Math.PI/180),D=60+40*Math.cos(L),N=60+40*Math.sin(L);return i.jsxs("g",{children:[T<Cn.length-1&&i.jsx("line",{x1:D,y1:N,x2:60+40*Math.cos(((T+1)*90-90)*(Math.PI/180)),y2:60+40*Math.sin(((T+1)*90-90)*(Math.PI/180)),stroke:R?"#3D52A0":"#ADBBDA",strokeWidth:R?2:1,strokeDasharray:R?"none":"4 3"}),T===Cn.length-1&&i.jsx("line",{x1:D,y1:N,x2:60+40*Math.cos(-90*(Math.PI/180)),y2:60+40*Math.sin(-90*(Math.PI/180)),stroke:"#ADBBDA",strokeWidth:1,strokeDasharray:"4 3"}),i.jsx("circle",{cx:D,cy:N,r:M?14:10,fill:M?"#3D52A0":R?"#7091E6":"#EDE8F5",stroke:M?"#6C63FF":R?"#3D52A0":"#ADBBDA",strokeWidth:M?3:1.5,className:M?"phase-active":""}),i.jsx("text",{x:D,y:N+(T===0?-20:T===2?24:0),textAnchor:"middle",className:"text-[9px] font-semibold fill-charcoal",dx:T===1?22:T===3?-22:0,children:o.label[0]})]},o.key)}),i.jsx("text",{x:"60",y:"64",textAnchor:"middle",className:"text-lg font-bold font-mono fill-primary",children:g})]})}),i.jsx("div",{className:"space-y-2",children:Cn.map(o=>{const T=o.key===p;return i.jsxs("div",{className:`flex items-center gap-3 px-3 py-2 rounded-xl transition-all duration-200 ${T?"bg-primary/8 border border-primary/20":"opacity-50"}`,children:[i.jsx("div",{className:`w-2.5 h-2.5 rounded-full flex-shrink-0 ${T?"bg-primary phase-active":"bg-surface"}`}),i.jsxs("div",{children:[i.jsx("span",{className:`text-sm font-semibold ${T?"text-primary":"text-slate"}`,children:o.label}),T&&i.jsx("p",{className:"text-xs text-slate mt-0.5",children:o.description})]})]},o.key)})})]})}const Od={architect:"bg-accent-product/10 text-accent-product border-accent-product/20",developer:"bg-primary/10 text-primary border-primary/20",tester:"bg-success/10 text-success border-success/20",reviewer:"bg-warning/10 text-warning border-warning/20",planner:"bg-primary-wash/20 text-charcoal border-primary-wash/30",default:"bg-surface/30 text-slate border-surface/50"};function O0(f){const g=f.toLowerCase();for(const[p,o]of Object.entries(Od))if(g.includes(p))return o;return Od.default}function D0({agents:f,loading:g}){const p=(f==null?void 0:f.filter(T=>T.alive))||[],o=(f==null?void 0:f.filter(T=>!T.alive))||[];return i.jsxs("div",{className:"glass p-6",children:[i.jsxs("div",{className:"flex items-center justify-between mb-4",children:[i.jsx("h3",{className:"text-sm font-semibold text-charcoal uppercase tracking-wider",children:"Agents"}),i.jsxs("span",{className:"font-mono text-xs text-slate",children:[p.length," active"]})]}),g&&!f&&i.jsx("div",{className:"text-center py-8 text-slate text-sm",children:"Loading agents..."}),!g&&(f==null?void 0:f.length)===0&&i.jsxs("div",{className:"text-center py-8",children:[i.jsx("p",{className:"text-slate text-sm",children:"No agents running"}),i.jsx("p",{className:"text-primary-wash text-xs mt-1",children:"Start a build to spawn agents"})]}),p.length>0&&i.jsx("div",{className:"space-y-2 mb-4",children:p.map(T=>i.jsx(Dd,{agent:T},T.id))}),o.length>0&&i.jsxs("details",{className:"mt-3",children:[i.jsxs("summary",{className:"text-xs text-slate cursor-pointer hover:text-charcoal transition-colors",children:[o.length," completed"]}),i.jsx("div",{className:"space-y-1.5 mt-2",children:o.slice(0,10).map(T=>i.jsx(Dd,{agent:T,compact:!0},T.id))})]})]})}function Dd({agent:f,compact:g}){const p=O0(f.type||f.name);return g?i.jsxs("div",{className:"flex items-center gap-2 px-2 py-1 rounded-lg bg-white/30 text-xs",children:[i.jsx("div",{className:"w-1.5 h-1.5 rounded-full bg-slate/30"}),i.jsx("span",{className:"font-medium text-slate truncate",children:f.name||f.id}),i.jsx("span",{className:"text-primary-wash ml-auto",children:f.type})]}):i.jsxs("div",{className:`flex items-start gap-3 px-3 py-2.5 rounded-xl border ${p}`,children:[i.jsx("div",{className:"flex-shrink-0 mt-0.5",children:i.jsx("div",{className:`w-2.5 h-2.5 rounded-full ${f.alive?"bg-success phase-active":"bg-slate/30"}`})}),i.jsxs("div",{className:"flex-1 min-w-0",children:[i.jsxs("div",{className:"flex items-center gap-2",children:[i.jsx("span",{className:"text-sm font-semibold truncate",children:f.name||f.id}),f.type&&i.jsx("span",{className:"text-[10px] font-mono font-medium opacity-70",children:f.type})]}),f.task&&i.jsx("p",{className:"text-xs opacity-70 mt-0.5 truncate",children:f.task}),f.status&&f.status!=="unknown"&&i.jsx("span",{className:"inline-block text-[10px] font-mono mt-1 opacity-60",children:f.status})]}),f.pid&&i.jsxs("span",{className:"text-[10px] font-mono text-slate/50 flex-shrink-0",children:["PID ",f.pid]})]})}const U0={info:"text-primary-light",error:"text-danger",warning:"text-warning",debug:"text-slate",critical:"text-danger font-bold"};function C0(f){if(!f)return"";if(f.includes("T")||f.includes("-"))try{return new Date(f).toLocaleTimeString("en-US",{hour12:!1})}catch{return f}return f}function R0({logs:f,loading:g,subscribe:p}){const o=U.useRef(null),[T,M]=U.useState(!1),[R,L]=U.useState([]);U.useEffect(()=>p?p("log",Q=>{const ll=Q;ll!=null&&ll.line&&L(al=>{const F=[...al,{message:ll.line,timestamp:ll.timestamp||""}];return F.length>500?F.slice(-500):F})}):void 0,[p]);const D=(()=>{const O=R.map(F=>{let Nl="info";const xl=F.message.toLowerCase();return xl.includes("error")||xl.includes("fail")?Nl="error":xl.includes("warn")?Nl="warning":xl.includes("debug")&&(Nl="debug"),{timestamp:F.timestamp,level:Nl,message:F.message,source:"ws"}}),Q=f||[];if(O.length===0)return Q;if(Q.length===0)return O;const ll=new Set(O.map(F=>F.message));return[...Q.filter(F=>!ll.has(F.message)),...O]})();U.useEffect(()=>{!T&&o.current&&(o.current.scrollTop=o.current.scrollHeight)},[D,T]);const N=()=>{if(!o.current)return;const{scrollTop:O,scrollHeight:Q,clientHeight:ll}=o.current,al=Q-O-ll<50;M(!al)},q=()=>{var O;M(!1),(O=o.current)==null||O.scrollTo({top:o.current.scrollHeight,behavior:"smooth"})};return i.jsxs("div",{className:"glass p-0 overflow-hidden flex flex-col h-full",children:[i.jsxs("div",{className:"flex items-center justify-between px-4 py-3 border-b border-white/10",children:[i.jsx("h3",{className:"text-sm font-semibold text-charcoal uppercase tracking-wider",children:"Terminal"}),i.jsxs("div",{className:"flex items-center gap-3",children:[i.jsxs("span",{className:"font-mono text-xs text-slate",children:[D.length," lines"]}),i.jsx("button",{onClick:T?q:()=>M(!0),className:`text-xs font-medium px-2.5 py-1 rounded-lg border transition-colors ${T?"border-warning/40 text-warning bg-warning/5 hover:bg-warning/10":"border-primary/20 text-primary hover:bg-primary/5"}`,title:T?"Scroll locked -- click to resume auto-scroll":"Auto-scrolling -- click to lock",children:T?"Locked":"Live"}),T&&i.jsx("button",{onClick:q,className:"text-xs text-primary hover:text-primary-light transition-colors font-medium",children:"Jump to bottom"})]})]}),i.jsxs("div",{ref:o,onScroll:N,className:"flex-1 overflow-y-auto terminal-scroll bg-charcoal/[0.03] p-4 font-mono text-xs leading-relaxed min-h-[300px]",children:[g&&!f&&R.length===0&&i.jsx("div",{className:"text-slate animate-pulse",children:"Connecting to log stream..."}),D.length===0&&!g&&i.jsxs("div",{className:"text-slate/60",children:[i.jsx("p",{children:"No log output yet."}),i.jsx("p",{className:"mt-1",children:"Start a build to see terminal output here."})]}),D.map((O,Q)=>i.jsxs("div",{className:"flex gap-2 hover:bg-white/5 rounded px-1 -mx-1",children:[i.jsx("span",{className:"text-slate/40 flex-shrink-0 select-none w-16 text-right",children:C0(O.timestamp)}),i.jsx("span",{className:`flex-shrink-0 w-12 text-right uppercase text-[10px] font-semibold ${U0[O.level]||"text-slate"}`,children:O.level}),i.jsx("span",{className:`flex-1 break-all ${O.level==="error"||O.level==="critical"?"text-danger":"text-charcoal/80"}`,children:O.message})]},Q)),D.length>0&&i.jsx("div",{className:"terminal-cursor mt-1"})]})]})}const H0={pass:{badge:"bg-success/10 text-success border-success/20",dot:"bg-success",label:"Pass"},fail:{badge:"bg-danger/10 text-danger border-danger/20",dot:"bg-danger",label:"Fail"},skip:{badge:"bg-slate/10 text-slate border-slate/20",dot:"bg-slate/40",label:"Skip"},pending:{badge:"bg-warning/10 text-warning border-warning/20",dot:"bg-warning",label:"Pending"}};function B0({item:f}){const[g,p]=U.useState(!1),o=H0[f.status];return i.jsxs("div",{className:`border rounded-xl overflow-hidden ${o.badge}`,children:[i.jsxs("button",{type:"button",className:"w-full flex items-center gap-3 px-3 py-2.5 text-left",onClick:()=>f.details&&p(!g),children:[i.jsx("span",{className:`w-2 h-2 rounded-full flex-shrink-0 ${o.dot}`}),i.jsx("span",{className:"text-sm font-medium flex-1 truncate",children:f.label}),i.jsx("span",{className:"text-[10px] font-mono font-semibold uppercase tracking-wider flex-shrink-0",children:o.label}),f.details&&i.jsx("span",{className:"text-xs text-slate/60 flex-shrink-0",children:g?"v":">"})]}),g&&f.details&&i.jsx("div",{className:"px-3 pb-2.5 pt-0",children:i.jsx("p",{className:"text-xs font-mono opacity-70 leading-relaxed",children:f.details})})]})}function q0({checklist:f,loading:g}){const p=f&&f.total>0?f.passed/f.total*100:0;return i.jsxs("div",{className:"glass p-6",children:[i.jsxs("div",{className:"flex items-center justify-between mb-4",children:[i.jsx("h3",{className:"text-sm font-semibold text-charcoal uppercase tracking-wider",children:"Quality Gates"}),f&&i.jsxs("span",{className:"font-mono text-xs text-slate",children:[f.passed,"/",f.total," passed"]})]}),g&&!f&&i.jsx("div",{className:"text-center py-8 text-slate text-sm",children:"Loading gates..."}),!g&&!f&&i.jsxs("div",{className:"text-center py-8",children:[i.jsx("p",{className:"text-slate text-sm",children:"No quality gate data"}),i.jsx("p",{className:"text-primary-wash text-xs mt-1",children:"Gates run during verification phase"})]}),f&&i.jsxs(i.Fragment,{children:[i.jsxs("div",{className:"flex items-center gap-4 mb-3 text-xs",children:[i.jsxs("span",{className:"text-success font-medium",children:[f.passed," passed"]}),f.failed>0&&i.jsxs("span",{className:"text-danger font-medium",children:[f.failed," failed"]}),f.skipped>0&&i.jsxs("span",{className:"text-slate",children:[f.skipped," skipped"]}),f.pending>0&&i.jsxs("span",{className:"text-warning",children:[f.pending," pending"]})]}),i.jsx("div",{className:"w-full h-2 bg-charcoal/10 rounded-full overflow-hidden mb-4",children:i.jsx("div",{className:"h-full bg-success rounded-full transition-all duration-500",style:{width:`${p}%`}})}),i.jsx("div",{className:"space-y-2 max-h-[400px] overflow-y-auto terminal-scroll",children:f.items.map(o=>i.jsx(B0,{item:o},o.id))})]})]})}const Y0={".py":"bg-success",".ts":"bg-primary",".tsx":"bg-primary",".md":"bg-warning",".sh":"bg-accent-product"};function G0(f){const g=f.substring(f.lastIndexOf("."));return Y0[g]||"bg-slate"}function w0(f){return f==null?"":f<1024?`${f}B`:f<1024*1024?`${(f/1024).toFixed(1)}KB`:`${(f/(1024*1024)).toFixed(1)}MB`}function Hd({node:f,depth:g,onSelectFile:p,selectedPath:o}){const[T,M]=U.useState(!1),R=f.type==="directory",L=f.path===o;return i.jsxs("div",{children:[i.jsxs("button",{type:"button",className:`w-full flex items-center gap-2 px-2 py-1 rounded-lg text-left text-sm transition-colors hover:bg-white/30 ${L?"bg-primary/10 text-primary":"text-charcoal"}`,style:{paddingLeft:`${g*16+8}px`},onClick:()=>{R?M(!T):p(f.path)},children:[R?i.jsx("span",{className:"font-mono text-xs text-slate w-3 flex-shrink-0",children:T?"v":">"}):i.jsx("span",{className:`w-2 h-2 rounded-full flex-shrink-0 ${G0(f.name)}`}),i.jsx("span",{className:`truncate ${R?"font-medium":"font-mono text-xs"}`,children:f.name}),!R&&f.size!==void 0&&i.jsx("span",{className:"ml-auto text-[10px] font-mono text-slate/60 flex-shrink-0",children:w0(f.size)})]}),R&&T&&f.children&&f.children.length>0&&i.jsx("div",{children:f.children.map(D=>i.jsx(Hd,{node:D,depth:g+1,onSelectFile:p,selectedPath:o},D.path))})]})}function Q0({files:f,loading:g}){const[p,o]=U.useState(null),[T,M]=U.useState(null),[R,L]=U.useState(!1),[D,N]=U.useState(null),q=U.useCallback(async Q=>{M(null),o(Q),L(!0),N(null);try{const ll=await ql.getFileContent(Q);M(ll.content)}catch(ll){const al=ll instanceof Error?ll.message:"Unknown error",F=ll instanceof TypeError||al==="Request timeout",Nl=al.includes("404")||al.includes("not found")||al.includes("Not found");N(F?"Network error - server may be unreachable":Nl?"File not found - it may have been deleted or renamed":al),M(null)}finally{L(!1)}},[]),O=U.useCallback(Q=>{q(Q)},[q]);return i.jsxs("div",{className:"glass p-6 flex flex-col",style:{minHeight:"300px"},children:[i.jsxs("div",{className:"flex items-center justify-between mb-4",children:[i.jsx("h3",{className:"text-sm font-semibold text-charcoal uppercase tracking-wider",children:"File Browser"}),i.jsx("span",{className:"font-mono text-xs text-slate",children:".loki/"})]}),g&&!f&&i.jsx("div",{className:"text-center py-8 text-slate text-sm",children:"Loading files..."}),!g&&(!f||f.length===0)&&i.jsxs("div",{className:"text-center py-8",children:[i.jsx("p",{className:"text-slate text-sm",children:"No project files found"}),i.jsx("p",{className:"text-primary-wash text-xs mt-1",children:"Start a session to generate .loki/ state"})]}),f&&f.length>0&&i.jsxs("div",{className:"flex gap-4 flex-1 min-h-0",children:[i.jsx("div",{className:"w-1/2 overflow-y-auto terminal-scroll pr-2",children:f.map(Q=>i.jsx(Hd,{node:Q,depth:0,onSelectFile:O,selectedPath:p},Q.path))}),i.jsxs("div",{className:"w-1/2 bg-charcoal/5 rounded-xl p-3 overflow-hidden flex flex-col",children:[!p&&i.jsx("div",{className:"flex-1 flex items-center justify-center text-slate text-xs",children:"Select a file to preview"}),p&&i.jsxs(i.Fragment,{children:[i.jsx("div",{className:"text-xs font-mono text-primary mb-2 truncate",children:p}),i.jsx("div",{className:"flex-1 overflow-y-auto terminal-scroll",children:R?i.jsx("div",{className:"text-slate text-xs",children:"Loading..."}):D?i.jsxs("div",{className:"flex flex-col items-center justify-center gap-2 py-6",children:[i.jsx("p",{className:"text-danger text-xs font-medium",children:"Failed to load file"}),i.jsx("p",{className:"text-slate text-[10px] text-center max-w-[200px] break-words",children:D}),i.jsx("button",{type:"button",onClick:()=>p&&q(p),className:"mt-1 px-3 py-1 text-[10px] font-semibold rounded-lg border border-primary/20 text-primary hover:bg-primary/5 transition-colors",children:"Retry"})]}):i.jsx("pre",{className:"text-xs font-mono text-charcoal whitespace-pre-wrap break-words leading-relaxed",children:T})})]})]})]})]})}const Ud=5e5;function Cd(f){return f>=1e6?`${(f/1e6).toFixed(1)}M`:f>=1e3?`${(f/1e3).toFixed(1)}K`:f.toString()}function X0(f){if(!f)return"Never";try{const g=new Date(f),o=new Date().getTime()-g.getTime(),T=Math.floor(o/(1e3*60*60));return T<1?"Just now":T<24?`${T}h ago`:`${Math.floor(T/24)}d ago`}catch{return f}}function L0({memory:f,loading:g}){const p=f?[{label:"Episodic",count:f.episodic_count,color:"text-primary",bg:"bg-primary/10",border:"border-primary/20"},{label:"Semantic",count:f.semantic_count,color:"text-success",bg:"bg-success/10",border:"border-success/20"},{label:"Skills",count:f.skill_count,color:"text-warning",bg:"bg-warning/10",border:"border-warning/20"}]:[],o=f?Math.min(f.total_tokens/Ud*100,100):0;return i.jsxs("div",{className:"glass p-6",children:[i.jsxs("div",{className:"flex items-center justify-between mb-4",children:[i.jsx("h3",{className:"text-sm font-semibold text-charcoal uppercase tracking-wider",children:"Memory System"}),f&&i.jsx("span",{className:"font-mono text-xs text-slate",children:X0(f.last_consolidation)})]}),g&&!f&&i.jsx("div",{className:"text-center py-8 text-slate text-sm",children:"Loading memory..."}),!g&&!f&&i.jsxs("div",{className:"text-center py-8",children:[i.jsx("p",{className:"text-slate text-sm",children:"No memory data available"}),i.jsx("p",{className:"text-primary-wash text-xs mt-1",children:"Memory populates during autonomous runs"})]}),f&&i.jsxs(i.Fragment,{children:[i.jsx("div",{className:"grid grid-cols-3 gap-3 mb-4",children:p.map(T=>i.jsxs("div",{className:`${T.bg} border ${T.border} rounded-xl p-3 text-center`,children:[i.jsx("div",{className:`text-2xl font-bold font-mono ${T.color}`,children:T.count}),i.jsx("div",{className:"text-[10px] text-slate font-medium mt-1 uppercase tracking-wider",children:T.label})]},T.label))}),i.jsxs("div",{className:"mt-3",children:[i.jsxs("div",{className:"flex items-center justify-between mb-1.5",children:[i.jsx("span",{className:"text-xs text-slate font-medium",children:"Token Usage"}),i.jsxs("span",{className:"text-xs font-mono text-charcoal",children:[Cd(f.total_tokens)," / ",Cd(Ud)]})]}),i.jsx("div",{className:"w-full h-2 bg-charcoal/10 rounded-full overflow-hidden",children:i.jsx("div",{className:`h-full rounded-full transition-all duration-500 ${o>80?"bg-danger":o>50?"bg-warning":"bg-primary-light"}`,style:{width:`${o}%`}})})]}),i.jsxs("div",{className:"mt-3 flex items-center justify-between text-xs",children:[i.jsx("span",{className:"text-slate",children:"Last Consolidation"}),i.jsx("span",{className:"font-mono text-charcoal",children:f.last_consolidation?new Date(f.last_consolidation).toLocaleString():"Never"})]})]})]})}function Z0({visible:f}){const[g,p]=U.useState("markdown"),[o,T]=U.useState(null),[M,R]=U.useState(null),[L,D]=U.useState(!1),[N,q]=U.useState(!1),[O,Q]=U.useState(null),[ll,al]=U.useState(!1);if(!f)return null;const F=async()=>{D(!0),Q(null),T(null),R(null);try{const J=await ql.generateReport(g);T(J)}catch(J){Q(J instanceof Error?J.message:"Failed to generate report")}finally{D(!1)}},Nl=async()=>{q(!0),Q(null);try{const J=await ql.shareSession();R(J)}catch(J){Q(J instanceof Error?J.message:"Failed to share session")}finally{q(!1)}},xl=async J=>{try{await navigator.clipboard.writeText(J),al(!0),setTimeout(()=>al(!1),2e3)}catch{}},gl=()=>{if(!o)return;const J=new Blob([o.content],{type:g==="html"?"text/html":"text/markdown"}),jl=URL.createObjectURL(J),Ol=document.createElement("a");Ol.href=jl,Ol.download=`loki-report.${g==="html"?"html":"md"}`,Ol.click(),URL.revokeObjectURL(jl)};return i.jsxs("div",{className:"glass p-4 rounded-2xl",children:[i.jsxs("div",{className:"flex items-center justify-between mb-3",children:[i.jsx("h3",{className:"text-sm font-semibold text-charcoal uppercase tracking-wider",children:"Session Report"}),i.jsxs("div",{className:"flex items-center gap-2",children:[i.jsx("div",{className:"flex items-center gap-1 glass-subtle rounded-xl p-1",children:["markdown","html"].map(J=>i.jsx("button",{onClick:()=>p(J),className:`px-3 py-1 text-xs font-semibold rounded-lg transition-all ${g===J?"bg-accent-product text-white shadow-sm":"text-slate hover:text-charcoal hover:bg-white/40"}`,children:J.toUpperCase()},J))}),i.jsx("button",{onClick:F,disabled:L,className:"px-4 py-1.5 rounded-xl text-xs font-semibold bg-accent-product text-white hover:bg-accent-product/90 disabled:opacity-50 transition-all",children:L?"Generating...":"Generate Report"})]})]}),O&&i.jsx("div",{className:"mb-3 px-3 py-2 rounded-lg bg-danger/10 border border-danger/20 text-danger text-xs",children:O}),o&&i.jsxs("div",{className:"mt-3",children:[i.jsxs("div",{className:"flex items-center gap-2 mb-2",children:[i.jsxs("span",{className:"text-xs text-slate",children:["Report generated (",o.format,")"]}),i.jsx("div",{className:"flex-1"}),i.jsx("button",{onClick:()=>xl(o.content),className:"px-3 py-1 text-xs font-medium text-slate hover:text-charcoal border border-white/30 rounded-lg hover:bg-white/30 transition-all",children:ll?"Copied":"Copy"}),i.jsx("button",{onClick:gl,className:"px-3 py-1 text-xs font-medium text-slate hover:text-charcoal border border-white/30 rounded-lg hover:bg-white/30 transition-all",children:"Download"}),i.jsx("button",{onClick:Nl,disabled:N,className:"px-3 py-1 text-xs font-medium bg-accent-product/10 text-accent-product border border-accent-product/20 rounded-lg hover:bg-accent-product/20 disabled:opacity-50 transition-all",children:N?"Sharing...":"Share as Gist"})]}),M&&i.jsxs("div",{className:"mb-2 flex items-center gap-2 px-3 py-2 rounded-lg bg-success/10 border border-success/20",children:[i.jsx("span",{className:"text-xs text-success font-medium",children:"Shared:"}),M.url?i.jsx("a",{href:M.url,target:"_blank",rel:"noopener noreferrer",className:"text-xs text-accent-product underline flex-1 truncate",children:M.url}):i.jsx("span",{className:"text-xs text-slate flex-1",children:"No URL returned"}),M.url&&i.jsx("button",{onClick:()=>xl(M.url),className:"text-xs text-slate hover:text-charcoal",children:"Copy URL"})]}),i.jsx("pre",{className:"text-[11px] font-mono text-charcoal bg-black/5 rounded-xl p-3 overflow-auto max-h-64 whitespace-pre-wrap terminal-scroll",children:o.content||"(empty report)"})]})]})}function Rd({visible:f}){const g=U.useCallback(()=>ql.getMetrics(),[]),{data:p,loading:o}=Ra(g,15e3,f);return f?i.jsxs("div",{className:"glass p-4 rounded-2xl",children:[i.jsxs("div",{className:"flex items-center justify-between mb-3",children:[i.jsx("h3",{className:"text-sm font-semibold text-charcoal uppercase tracking-wider",children:"Session Metrics"}),o&&i.jsx("div",{className:"w-4 h-4 border-2 border-accent-product border-t-transparent rounded-full animate-spin"})]}),p?i.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[i.jsxs("div",{className:"glass-subtle rounded-xl p-3",children:[i.jsx("div",{className:"text-[10px] font-semibold text-slate uppercase tracking-wider mb-1",children:"Iterations"}),i.jsx("div",{className:"text-xl font-bold text-charcoal",children:p.iterations??0})]}),i.jsxs("div",{className:"glass-subtle rounded-xl p-3",children:[i.jsx("div",{className:"text-[10px] font-semibold text-slate uppercase tracking-wider mb-1",children:"Gate Pass Rate"}),i.jsx("div",{className:"text-xl font-bold text-charcoal",children:typeof p.quality_gate_pass_rate=="number"?`${p.quality_gate_pass_rate.toFixed(0)}%`:"N/A"})]}),i.jsxs("div",{className:"glass-subtle rounded-xl p-3",children:[i.jsx("div",{className:"text-[10px] font-semibold text-slate uppercase tracking-wider mb-1",children:"Tokens Used"}),i.jsx("div",{className:"text-xl font-bold text-charcoal",children:(p.tokens_used??0).toLocaleString()})]}),i.jsxs("div",{className:"glass-subtle rounded-xl p-3",children:[i.jsx("div",{className:"text-[10px] font-semibold text-slate uppercase tracking-wider mb-1",children:"Time Elapsed"}),i.jsx("div",{className:"text-xl font-bold text-charcoal",children:p.time_elapsed||"N/A"})]})]}):i.jsx("div",{className:"text-sm text-slate py-4 text-center",children:o?"Loading metrics...":"No metrics available"})]}):null}const V0={completed:{bg:"bg-success/10",text:"text-success",label:"Completed"},complete:{bg:"bg-success/10",text:"text-success",label:"Completed"},done:{bg:"bg-success/10",text:"text-success",label:"Completed"},in_progress:{bg:"bg-primary/10",text:"text-primary",label:"In Progress"},started:{bg:"bg-warning/10",text:"text-warning",label:"Started"},error:{bg:"bg-danger/10",text:"text-danger",label:"Failed"},failed:{bg:"bg-danger/10",text:"text-danger",label:"Failed"},empty:{bg:"bg-slate/10",text:"text-slate",label:"Empty"}};function K0(f){return V0[f]||{bg:"bg-slate/10",text:"text-slate",label:f}}function J0({onLoadSession:f}){const g=U.useCallback(()=>ql.getSessionsHistory(),[]),{data:p,loading:o}=Ra(g,6e4,!0);return o&&!p?i.jsxs("div",{className:"glass p-4 rounded-2xl",children:[i.jsx("h3",{className:"text-sm font-semibold text-charcoal uppercase tracking-wider mb-3",children:"Past Builds"}),i.jsx("div",{className:"text-sm text-slate",children:"Loading..."})]}):!p||p.length===0?null:i.jsxs("div",{className:"glass p-4 rounded-2xl",children:[i.jsx("h3",{className:"text-sm font-semibold text-charcoal uppercase tracking-wider mb-3",children:"Past Builds"}),i.jsx("div",{className:"flex flex-col gap-2 max-h-64 overflow-y-auto terminal-scroll",children:p.map(T=>{const M=K0(T.status),R=T.file_count;return i.jsxs("button",{onClick:()=>f==null?void 0:f(T),className:"text-left px-4 py-3 rounded-xl glass-subtle hover:bg-white/40 transition-all group cursor-pointer",children:[i.jsxs("div",{className:"flex items-center justify-between mb-1",children:[i.jsx("span",{className:"text-[10px] font-mono text-slate",children:T.date}),i.jsxs("div",{className:"flex items-center gap-2",children:[R!==void 0&&R>0&&i.jsxs("span",{className:"text-[10px] font-mono text-slate",children:[R," files"]}),i.jsx("span",{className:`text-[10px] font-semibold px-2 py-0.5 rounded-full ${M.bg} ${M.text}`,children:M.label})]})]}),i.jsx("div",{className:"text-xs text-charcoal truncate group-hover:text-accent-product transition-colors",children:T.prd_snippet||T.id}),i.jsx("div",{className:"text-[10px] font-mono text-slate/60 mt-0.5 truncate",children:T.path})]},T.id)})})]})}function k0(){const[f,g]=U.useState(null),[p,o]=U.useState(!1),[T,M]=U.useState(!1),[R,L]=U.useState(null),[D,N]=U.useState(!1),[q,O]=U.useState(!1),[Q,ll]=U.useState(!1),[al,F]=U.useState("terminal"),[Nl,xl]=U.useState("claude"),[gl,J]=U.useState(null),[jl,Ol]=U.useState(null),[Al,k]=U.useState(null),[Yl,wl]=U.useState(null),tt=U.useCallback(pl=>{if(!pl){Ol(null),k(null),wl(null);return}Ol(pl.status),k(pl.agents),wl(pl.logs),o(pl.status.running??!1),M(pl.status.paused??!1)},[]),{connected:Ql,subscribe:Xl}=p0(tt),ft=U.useCallback(()=>ql.getStatus(),[]),{data:Vl}=Ra(ft,3e4,!Ql);U.useEffect(()=>{jl===null&&Vl!==null&&(o(Vl.running??!1),M(Vl.paused??!1))},[Vl,jl]),U.useEffect(()=>{p&&N(!0)},[p]);const Pl=U.useCallback(()=>ql.getMemorySummary(),[]),S=U.useCallback(()=>ql.getChecklist(),[]),_=U.useCallback(()=>ql.getFiles(),[]),{data:G,loading:ul}=Ra(Pl,3e4,p),{data:ol,loading:m}=Ra(S,3e4,p),{data:A,loading:C}=Ra(_,3e4,p),H=jl??Vl,Z=Al,W=Yl,cl=Al===null,Kl=Yl===null,El=U.useCallback(async(pl,Yt,Hn,Ba)=>{g(null),N(!1),O(!1),F("terminal");try{await ql.startSession({prd:pl,provider:Yt,projectDir:Hn,mode:Ba}),L(pl)}catch($e){g($e instanceof Error?$e.message:"Failed to start session")}},[]),_e=U.useCallback(async()=>{try{(await ql.stopSession()).stopped&&(o(!1),M(!1),L(null),Ol(null),k(null),wl(null))}catch{o(!1),M(!1),L(null)}},[]),Je=U.useCallback(async pl=>{try{const Yt=await ql.getSessionDetail(pl.id);J(Yt)}catch{}},[]),ke=U.useCallback(pl=>{xl(pl)},[]),Rn=U.useCallback(async()=>{try{await ql.pauseSession(),M(!0)}catch{}},[]),qt=U.useCallback(async()=>{try{await ql.resumeSession(),M(!1)}catch{}},[]),Ha=R&&R.replace(/^#+\s*/gm,"").split(`
66
66
  `).find(pl=>pl.trim().length>0)||null;return i.jsxs("div",{className:"min-h-screen bg-background relative",children:[i.jsx("div",{className:"pattern-circles"}),i.jsx(S0,{status:H,wsConnected:Ql,onProviderChange:ke,selectedProvider:Nl}),i.jsx("main",{className:"max-w-[1920px] mx-auto px-6 py-6 relative z-10",children:p?i.jsxs(i.Fragment,{children:[i.jsx(T0,{status:H,prdSummary:Ha,onStop:_e,onPause:Rn,onResume:qt,isPaused:T}),i.jsx("div",{className:"mt-4",children:i.jsx(E0,{status:H})}),i.jsxs("div",{className:"mt-4 grid grid-cols-12 gap-6",style:{minHeight:"calc(100vh - 340px)"},children:[i.jsx("div",{className:"col-span-3 flex flex-col gap-6",children:i.jsx(M0,{currentPhase:(H==null?void 0:H.phase)||"idle",iteration:(H==null?void 0:H.iteration)||0})}),i.jsxs("div",{className:"col-span-5 flex flex-col gap-0",children:[i.jsxs("div",{className:"flex items-center gap-1 mb-2",children:[i.jsx("button",{onClick:()=>F("terminal"),className:`px-3 py-1.5 text-xs font-semibold rounded-lg transition-all ${al==="terminal"?"bg-accent-product text-white":"text-slate hover:text-charcoal hover:bg-white/30"}`,children:"Terminal"}),i.jsx("button",{onClick:()=>F("metrics"),className:`px-3 py-1.5 text-xs font-semibold rounded-lg transition-all ${al==="metrics"?"bg-accent-product text-white":"text-slate hover:text-charcoal hover:bg-white/30"}`,children:"Metrics"})]}),al==="terminal"?i.jsx(R0,{logs:W,loading:Kl,subscribe:Xl}):i.jsx(Rd,{visible:!0})]}),i.jsxs("div",{className:"col-span-4 flex flex-col gap-6",children:[i.jsx(D0,{agents:Z,loading:cl}),i.jsx(q0,{checklist:ol,loading:m})]})]}),i.jsxs("div",{className:"mt-6 grid grid-cols-12 gap-6",children:[i.jsx("div",{className:"col-span-6",children:i.jsx(Q0,{files:A,loading:C})}),i.jsx("div",{className:"col-span-6",children:i.jsx(L0,{memory:G,loading:ul})})]})]}):i.jsxs("div",{className:"flex flex-col items-center",children:[i.jsxs("div",{className:"text-center mt-8 mb-8",children:[i.jsx("h2",{className:"text-3xl font-bold text-charcoal tracking-tight",children:"Describe it. Build it. Ship it."}),i.jsx("p",{className:"text-slate mt-2 text-base max-w-lg mx-auto",children:"Paste a PRD or pick a template. Purple Lab spins up autonomous agents to build your project from scratch."})]}),i.jsx("div",{className:"w-full max-w-3xl",children:i.jsx(A0,{onSubmit:El,running:p,error:f,provider:Nl,onProviderChange:ke})}),D&&!p&&i.jsxs("div",{className:"w-full max-w-3xl mt-4 flex flex-col gap-4",children:[i.jsxs("div",{className:"flex items-center gap-3",children:[i.jsx("button",{onClick:()=>O(!q),className:"px-4 py-2 rounded-xl text-sm font-semibold border border-accent-product/30 text-accent-product hover:bg-accent-product/5 transition-all",children:q?"Hide Report Panel":"Report"}),i.jsx("button",{onClick:()=>ll(!Q),className:"px-4 py-2 rounded-xl text-sm font-semibold border border-white/30 text-slate hover:text-charcoal hover:bg-white/30 transition-all",children:Q?"Hide Metrics":"View Metrics"})]}),i.jsx(Z0,{visible:q}),i.jsx(Rd,{visible:Q})]}),gl&&i.jsx("div",{className:"w-full max-w-3xl mt-4",children:i.jsxs("div",{className:"glass p-4 rounded-2xl",children:[i.jsxs("div",{className:"flex items-center justify-between mb-3",children:[i.jsxs("h3",{className:"text-sm font-semibold text-charcoal uppercase tracking-wider",children:["Session: ",gl.id]}),i.jsx("button",{onClick:()=>J(null),className:"text-xs text-slate hover:text-charcoal transition-colors px-2 py-1 rounded-lg hover:bg-white/30",children:"Close"})]}),i.jsx("div",{className:"text-[10px] font-mono text-slate mb-3",children:gl.path}),gl.prd&&i.jsxs("div",{className:"mb-3",children:[i.jsx("div",{className:"text-[10px] text-slate uppercase tracking-wider font-semibold mb-1",children:"PRD"}),i.jsxs("div",{className:"bg-charcoal/[0.03] rounded-lg p-3 font-mono text-xs text-charcoal/80 max-h-32 overflow-y-auto terminal-scroll whitespace-pre-wrap",children:[gl.prd.slice(0,500),gl.prd.length>500?"...":""]})]}),gl.files.length>0&&i.jsxs("div",{className:"mb-3",children:[i.jsxs("div",{className:"text-[10px] text-slate uppercase tracking-wider font-semibold mb-1",children:["Files (",gl.files.length,")"]}),i.jsx("div",{className:"bg-charcoal/[0.03] rounded-lg p-3 font-mono text-xs max-h-40 overflow-y-auto terminal-scroll",children:gl.files.map((pl,Yt)=>i.jsx("div",{className:"text-charcoal/70",children:pl.type==="directory"?`${pl.name}/`:pl.name},Yt))})]}),gl.logs.length>0&&i.jsxs("div",{children:[i.jsxs("div",{className:"text-[10px] text-slate uppercase tracking-wider font-semibold mb-1",children:["Logs (",gl.logs.length," lines)"]}),i.jsx("div",{className:"bg-charcoal/[0.03] rounded-lg p-3 font-mono text-[10px] max-h-40 overflow-y-auto terminal-scroll",children:gl.logs.map((pl,Yt)=>i.jsx("div",{className:"text-charcoal/70",children:pl},Yt))})]})]})}),i.jsx("div",{className:"w-full max-w-3xl mt-4",children:i.jsx(J0,{onLoadSession:Je})}),i.jsxs("div",{className:"mt-6 text-xs text-slate flex items-center gap-2",children:[i.jsx("div",{className:`w-2 h-2 rounded-full ${Ql?"bg-success":"bg-danger"}`}),Ql?"Connected to Purple Lab backend":"Waiting for backend connection..."]})]})})]})}v0.createRoot(document.getElementById("root")).render(i.jsx(U.StrictMode,{children:i.jsx(k0,{})}));
@@ -8,7 +8,7 @@
8
8
  <link rel="preconnect" href="https://fonts.googleapis.com">
9
9
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
10
10
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
11
- <script type="module" crossorigin src="/assets/index-BVw_Fxig.js"></script>
11
+ <script type="module" crossorigin src="/assets/index-Bwj6Ubaa.js"></script>
12
12
  <link rel="stylesheet" crossorigin href="/assets/index-CDiM5Vh4.css">
13
13
  </head>
14
14
  <body class="bg-background text-charcoal font-sans antialiased">