loki-mode 6.37.6 → 6.37.7
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 +2 -2
- package/VERSION +1 -1
- package/autonomy/loki +74 -103
- package/autonomy/run.sh +6 -0
- package/completions/_loki +27 -11
- package/completions/loki.bash +9 -4
- package/dashboard/__init__.py +1 -1
- package/dashboard/server.py +82 -4
- package/docs/INSTALLATION.md +1 -1
- package/mcp/__init__.py +1 -1
- package/package.json +1 -1
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
|
+
# Loki Mode v6.37.7
|
|
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.
|
|
270
|
+
**v6.37.7 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
6.37.
|
|
1
|
+
6.37.7
|
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 "
|
|
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
|
-
|
|
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
|
-
|
|
13180
|
-
|
|
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
|
|
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("
|
|
14625
|
+
with open(os.environ["TYPES_FILE"]) as f:
|
|
14655
14626
|
agents = json.load(f)
|
|
14656
14627
|
|
|
14657
|
-
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 = "
|
|
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("
|
|
14667
|
+
with open(os.environ["TYPES_FILE"]) as f:
|
|
14697
14668
|
agents = json.load(f)
|
|
14698
14669
|
|
|
14699
|
-
target = "
|
|
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
|
-
|
|
48
|
-
|
|
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
|
-
'
|
|
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
|
|
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
|
-
'
|
|
301
|
-
'
|
|
302
|
-
'
|
|
303
|
-
'
|
|
304
|
-
'
|
|
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 '
|
|
323
|
+
_describe -t cmds 'agent subcommand' cmds
|
|
308
324
|
}
|
|
309
325
|
|
|
310
326
|
function _loki_reset {
|
package/completions/loki.bash
CHANGED
|
@@ -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
|
|
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
|
-
|
|
87
|
-
local
|
|
88
|
-
COMPREPLY=( $(compgen -W "${
|
|
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)
|
package/dashboard/__init__.py
CHANGED
package/dashboard/server.py
CHANGED
|
@@ -2662,10 +2662,43 @@ async def pause_session():
|
|
|
2662
2662
|
"""Pause the current session by creating PAUSE file."""
|
|
2663
2663
|
if not _control_limiter.check("control"):
|
|
2664
2664
|
raise HTTPException(status_code=429, detail="Rate limit exceeded")
|
|
2665
|
-
|
|
2665
|
+
|
|
2666
|
+
loki_dir = _get_loki_dir()
|
|
2667
|
+
pid_file = loki_dir / "loki.pid"
|
|
2668
|
+
|
|
2669
|
+
# Verify loki process is running before attempting pause
|
|
2670
|
+
process_running = False
|
|
2671
|
+
if pid_file.exists():
|
|
2672
|
+
try:
|
|
2673
|
+
pid = int(pid_file.read_text().strip())
|
|
2674
|
+
os.kill(pid, 0) # Signal 0: check existence without killing
|
|
2675
|
+
process_running = True
|
|
2676
|
+
except (ValueError, OSError, ProcessLookupError):
|
|
2677
|
+
pass
|
|
2678
|
+
|
|
2679
|
+
pause_file = loki_dir / "PAUSE"
|
|
2666
2680
|
pause_file.parent.mkdir(parents=True, exist_ok=True)
|
|
2667
2681
|
pause_file.write_text(datetime.now(timezone.utc).isoformat())
|
|
2668
|
-
|
|
2682
|
+
|
|
2683
|
+
if not process_running:
|
|
2684
|
+
return JSONResponse(
|
|
2685
|
+
status_code=503,
|
|
2686
|
+
content={"success": False, "message": "Session process is not running; pause signal may have no effect"},
|
|
2687
|
+
)
|
|
2688
|
+
|
|
2689
|
+
# Poll up to 5s to confirm process is still alive with PAUSE file present
|
|
2690
|
+
for _ in range(10):
|
|
2691
|
+
try:
|
|
2692
|
+
os.kill(pid, 0)
|
|
2693
|
+
return {"success": True, "message": "Session paused", "process_verified": True}
|
|
2694
|
+
except OSError:
|
|
2695
|
+
break
|
|
2696
|
+
await asyncio.sleep(0.5)
|
|
2697
|
+
|
|
2698
|
+
return JSONResponse(
|
|
2699
|
+
status_code=503,
|
|
2700
|
+
content={"success": False, "message": "Session process exited unexpectedly after pause signal"},
|
|
2701
|
+
)
|
|
2669
2702
|
|
|
2670
2703
|
|
|
2671
2704
|
@app.post("/api/control/resume", dependencies=[Depends(auth.require_scope("control"))])
|
|
@@ -2673,13 +2706,58 @@ async def resume_session():
|
|
|
2673
2706
|
"""Resume a paused session by removing PAUSE/STOP files."""
|
|
2674
2707
|
if not _control_limiter.check("control"):
|
|
2675
2708
|
raise HTTPException(status_code=429, detail="Rate limit exceeded")
|
|
2709
|
+
|
|
2710
|
+
loki_dir = _get_loki_dir()
|
|
2711
|
+
pid_file = loki_dir / "loki.pid"
|
|
2712
|
+
|
|
2713
|
+
# Verify loki process is running before attempting resume
|
|
2714
|
+
process_running = False
|
|
2715
|
+
pid = 0
|
|
2716
|
+
if pid_file.exists():
|
|
2717
|
+
try:
|
|
2718
|
+
pid = int(pid_file.read_text().strip())
|
|
2719
|
+
os.kill(pid, 0) # Signal 0: check existence without killing
|
|
2720
|
+
process_running = True
|
|
2721
|
+
except (ValueError, OSError, ProcessLookupError):
|
|
2722
|
+
pass
|
|
2723
|
+
|
|
2724
|
+
if not process_running:
|
|
2725
|
+
# Still remove the files for cleanup, but return 503
|
|
2726
|
+
for fname in ["PAUSE", "STOP"]:
|
|
2727
|
+
fpath = loki_dir / fname
|
|
2728
|
+
try:
|
|
2729
|
+
fpath.unlink(missing_ok=True)
|
|
2730
|
+
except Exception:
|
|
2731
|
+
pass
|
|
2732
|
+
return JSONResponse(
|
|
2733
|
+
status_code=503,
|
|
2734
|
+
content={"success": False, "message": "Session did not respond to resume signal"},
|
|
2735
|
+
)
|
|
2736
|
+
|
|
2676
2737
|
for fname in ["PAUSE", "STOP"]:
|
|
2677
|
-
fpath =
|
|
2738
|
+
fpath = loki_dir / fname
|
|
2678
2739
|
try:
|
|
2679
2740
|
fpath.unlink(missing_ok=True)
|
|
2680
2741
|
except Exception:
|
|
2681
2742
|
pass
|
|
2682
|
-
|
|
2743
|
+
|
|
2744
|
+
# Poll up to 5s to verify the process is still running and acknowledged the resume
|
|
2745
|
+
for _ in range(10):
|
|
2746
|
+
try:
|
|
2747
|
+
os.kill(pid, 0)
|
|
2748
|
+
if not (loki_dir / "PAUSE").exists():
|
|
2749
|
+
return {"success": True, "message": "Session resumed", "process_verified": True}
|
|
2750
|
+
except OSError:
|
|
2751
|
+
return JSONResponse(
|
|
2752
|
+
status_code=503,
|
|
2753
|
+
content={"success": False, "message": "Session did not respond to resume signal"},
|
|
2754
|
+
)
|
|
2755
|
+
await asyncio.sleep(0.5)
|
|
2756
|
+
|
|
2757
|
+
return JSONResponse(
|
|
2758
|
+
status_code=503,
|
|
2759
|
+
content={"success": False, "message": "Session did not respond to resume signal"},
|
|
2760
|
+
)
|
|
2683
2761
|
|
|
2684
2762
|
|
|
2685
2763
|
@app.post("/api/control/stop", dependencies=[Depends(auth.require_scope("control"))])
|
package/docs/INSTALLATION.md
CHANGED
package/mcp/__init__.py
CHANGED