loki-mode 5.53.0 → 5.55.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/autonomy/loki CHANGED
@@ -409,7 +409,8 @@ show_help() {
409
409
  echo " council [cmd] Completion council (status|verdicts|convergence|force-review|report)"
410
410
  echo " checkpoint|cp Save/restore session checkpoints"
411
411
  echo " projects Multi-project registry management"
412
- echo " audit Agent action audit log"
412
+ echo " audit [cmd] Agent audit log and quality scanning (log|scan)"
413
+ echo " optimize Optimize prompts based on session history"
413
414
  echo " enterprise Enterprise feature management (tokens, OIDC)"
414
415
  echo " metrics Prometheus/OpenMetrics metrics from dashboard"
415
416
  echo " dogfood Show self-development statistics"
@@ -431,6 +432,7 @@ show_help() {
431
432
  echo " --no-dashboard Disable web dashboard"
432
433
  echo " --sandbox Run in Docker sandbox for isolation"
433
434
  echo " --skip-memory Skip loading memory context at startup"
435
+ echo " --compliance PRESET Enable compliance mode (default|healthcare|fintech|government)"
434
436
  echo " --budget USD Set cost budget limit (display in dashboard/status)"
435
437
  echo ""
436
438
  echo "Options for 'issue':"
@@ -484,6 +486,7 @@ cmd_start() {
484
486
  echo " --no-dashboard Disable web dashboard"
485
487
  echo " --sandbox Run in Docker sandbox"
486
488
  echo " --skip-memory Skip loading memory context at startup"
489
+ echo " --compliance PRESET Enable compliance mode (default|healthcare|fintech|government)"
487
490
  echo " --budget USD Cost budget limit (auto-pause when exceeded)"
488
491
  echo " --yes, -y Skip confirmation prompts (auto-confirm)"
489
492
  echo ""
@@ -550,6 +553,22 @@ cmd_start() {
550
553
  export LOKI_SKIP_MEMORY=true
551
554
  shift
552
555
  ;;
556
+ --compliance)
557
+ if [[ -n "${2:-}" ]]; then
558
+ export LOKI_COMPLIANCE_PRESET="$2"
559
+ echo -e "${CYAN}Compliance mode: $2${NC}"
560
+ shift 2
561
+ else
562
+ echo -e "${RED}--compliance requires a preset name (default, healthcare, fintech, government)${NC}"
563
+ exit 1
564
+ fi
565
+ ;;
566
+ --compliance=*)
567
+ local compliance_val="${1#*=}"
568
+ export LOKI_COMPLIANCE_PRESET="$compliance_val"
569
+ echo -e "${CYAN}Compliance mode: $compliance_val${NC}"
570
+ shift
571
+ ;;
553
572
  --yes|-y)
554
573
  export LOKI_AUTO_CONFIRM=true
555
574
  shift
@@ -4688,6 +4707,794 @@ except Exception:
4688
4707
  esac
4689
4708
  }
4690
4709
 
4710
+ # Prompt optimization via dashboard API
4711
+ cmd_optimize() {
4712
+ local sessions=10
4713
+ local dry_run=""
4714
+
4715
+ while [[ $# -gt 0 ]]; do
4716
+ case "$1" in
4717
+ --sessions) if [[ -z "${2:-}" ]]; then echo -e "${RED}Error: --sessions requires a value${NC}"; exit 1; fi; sessions="$2"; shift 2 ;;
4718
+ --sessions=*) sessions="${1#*=}"; shift ;;
4719
+ --dry-run) dry_run="true"; shift ;;
4720
+ --help|-h)
4721
+ echo -e "${BOLD}loki optimize${NC} - Optimize prompts based on session history"
4722
+ echo ""
4723
+ echo "Usage: loki optimize [options]"
4724
+ echo ""
4725
+ echo "Analyzes recent session failures and proposes prompt improvements."
4726
+ echo "Requires the dashboard API to be running (loki serve)."
4727
+ echo ""
4728
+ echo "Options:"
4729
+ echo " --sessions N Number of recent sessions to analyze (default: 10)"
4730
+ echo " --dry-run Show proposed changes without applying"
4731
+ echo ""
4732
+ echo "Examples:"
4733
+ echo " loki optimize # Optimize using last 10 sessions"
4734
+ echo " loki optimize --sessions 20 # Analyze last 20 sessions"
4735
+ echo " loki optimize --dry-run # Preview changes only"
4736
+ exit 0
4737
+ ;;
4738
+ *)
4739
+ echo -e "${RED}Unknown option: $1${NC}"
4740
+ echo "Run 'loki optimize --help' for usage."
4741
+ exit 1
4742
+ ;;
4743
+ esac
4744
+ done
4745
+
4746
+ local port="${LOKI_DASHBOARD_PORT:-57374}"
4747
+ local host="127.0.0.1"
4748
+ local dry_run_param="false"
4749
+ if [ -n "$dry_run" ]; then
4750
+ dry_run_param="true"
4751
+ fi
4752
+ local url="http://${host}:${port}/api/prompt-optimize?sessions=${sessions}&dry_run=${dry_run_param}"
4753
+
4754
+ echo -e "${BOLD}Analyzing sessions for prompt optimization...${NC}"
4755
+ echo -e "${DIM}Sessions: $sessions | Dry run: ${dry_run_param}${NC}"
4756
+ echo ""
4757
+
4758
+ local response http_code
4759
+ response=$(curl -s -w "\n%{http_code}" -X POST "$url" 2>/dev/null) || true
4760
+ http_code=$(echo "$response" | tail -1)
4761
+ response=$(echo "$response" | sed '$d')
4762
+ if [ -z "$http_code" ] || [ "$http_code" = "000" ]; then
4763
+ echo -e "${RED}Error: Could not connect to dashboard API at http://${host}:${port}${NC}"
4764
+ echo "Make sure the dashboard is running: loki serve"
4765
+ exit 1
4766
+ fi
4767
+ if [ "$http_code" -ge 400 ] 2>/dev/null; then
4768
+ echo -e "${RED}Error: Dashboard API returned HTTP $http_code${NC}"
4769
+ [ -n "$response" ] && echo "$response"
4770
+ exit 1
4771
+ fi
4772
+
4773
+ if ! command -v python3 &>/dev/null; then
4774
+ echo "$response" | jq . 2>/dev/null || echo "$response"
4775
+ else
4776
+ echo "$response" | python3 -c "
4777
+ import json, sys
4778
+ data = json.loads(sys.stdin.read())
4779
+
4780
+ failures = data.get('failures_analyzed', 0)
4781
+ changes = data.get('changes', [])
4782
+ version = data.get('version', None)
4783
+
4784
+ print(f'Failures analyzed: {failures}')
4785
+ print(f'Changes proposed: {len(changes)}')
4786
+ print('---')
4787
+
4788
+ for i, change in enumerate(changes, 1):
4789
+ prompt = change.get('prompt', '?')
4790
+ rationale = change.get('rationale', 'No rationale provided')
4791
+ old = change.get('old_value', '')
4792
+ new = change.get('new_value', '')
4793
+ print(f'')
4794
+ print(f' {i}. {prompt}')
4795
+ print(f' Rationale: {rationale}')
4796
+ if old:
4797
+ print(f' Old: {old[:80]}...' if len(old) > 80 else f' Old: {old}')
4798
+ if new:
4799
+ print(f' New: {new[:80]}...' if len(new) > 80 else f' New: {new}')
4800
+
4801
+ if version is not None:
4802
+ print(f'')
4803
+ print(f'Prompts optimized to version {version}')
4804
+ elif not changes:
4805
+ print(f'')
4806
+ print('No optimization changes proposed.')
4807
+ print()
4808
+ " 2>/dev/null || echo "$response"
4809
+ fi
4810
+ }
4811
+
4812
+ # ============================================================================
4813
+ # Migration Command
4814
+ # ============================================================================
4815
+
4816
+ cmd_migrate_help() {
4817
+ echo -e "${BOLD}loki migrate${NC} - Codebase migration with autonomous agents"
4818
+ echo ""
4819
+ echo "Usage: loki migrate <path-to-codebase> [options]"
4820
+ echo ""
4821
+ echo "Migrates a codebase to a new language, framework, or architecture using"
4822
+ echo "multi-agent orchestration with guardrails and incremental verification."
4823
+ echo ""
4824
+ echo "Options:"
4825
+ echo " --target <lang|framework|arch> Migration target (e.g. typescript, react, microservices)"
4826
+ echo " --plan-only Generate migration plan without executing"
4827
+ echo " --show-plan Display current migration plan"
4828
+ echo " --phase <phase> Run specific phase:"
4829
+ echo " understand - Analyze codebase structure"
4830
+ echo " guardrail - Set up tests and safety nets"
4831
+ echo " migrate - Execute migration transforms"
4832
+ echo " verify - Run verification suite"
4833
+ echo " --parallel <N> Max parallel agents (default: 4, max: 10)"
4834
+ echo " --compliance <preset> Compliance preset: healthcare, fintech, government"
4835
+ echo " --dry-run Show what would change without executing"
4836
+ echo " --resume Resume from last checkpoint"
4837
+ echo " --multi-repo <glob> Multiple repository paths (glob pattern)"
4838
+ echo " --export-report Export migration report to file"
4839
+ echo " --list List all migrations"
4840
+ echo " --status [migration-id] Show migration status"
4841
+ echo ""
4842
+ echo "Examples:"
4843
+ echo " loki migrate ./my-app --target typescript"
4844
+ echo " loki migrate ./my-app --target react --plan-only"
4845
+ echo " loki migrate ./my-app --target microservices --compliance fintech"
4846
+ echo " loki migrate --list"
4847
+ echo " loki migrate --status mig-20260223-001"
4848
+ echo " loki migrate ./my-app --target typescript --resume"
4849
+ echo " loki migrate ./my-app --target typescript --phase verify"
4850
+ echo " loki migrate --multi-repo './services/*' --target typescript"
4851
+ }
4852
+
4853
+ cmd_migrate_list() {
4854
+ python3 -c "
4855
+ import sys
4856
+ sys.path.insert(0, '.')
4857
+ from dashboard.migration_engine import list_migrations
4858
+ migrations = list_migrations()
4859
+ if not migrations:
4860
+ print('No migrations found.')
4861
+ print('Start a migration with: loki migrate <path> --target <target>')
4862
+ else:
4863
+ print(f'\033[1mMigrations\033[0m ({len(migrations)} total)')
4864
+ print('---')
4865
+ for m in migrations:
4866
+ print(f\" {m['id']}\")
4867
+ print(f\" Target: {m.get('target', '?')}\")
4868
+ print(f\" Source: {m.get('source_path', '?')}\")
4869
+ print(f\" Status: {m.get('status', '?')}\")
4870
+ print(f\" Created: {m.get('created_at', '?')[:10] if m.get('created_at') else '?'}\")
4871
+ print()
4872
+ " || {
4873
+ echo -e "${RED}Error listing migrations${NC}"
4874
+ return 1
4875
+ }
4876
+ }
4877
+
4878
+ cmd_migrate_status() {
4879
+ local migration_id="${1:-}"
4880
+ local migrations_dir="${HOME}/.loki/migrations"
4881
+
4882
+ if [ -z "$migration_id" ]; then
4883
+ # Show status of most recent migration
4884
+ local latest
4885
+ latest=$(find "$migrations_dir" -name "manifest.json" -maxdepth 2 2>/dev/null | sort | tail -1)
4886
+ if [ -z "$latest" ]; then
4887
+ echo -e "${YELLOW}No migrations found.${NC}"
4888
+ return 0
4889
+ fi
4890
+ migration_id=$(python3 -c "import json, sys; print(json.load(open(sys.argv[1]))['id'])" "$latest" 2>/dev/null || echo "")
4891
+ fi
4892
+
4893
+ local manifest="${migrations_dir}/${migration_id}/manifest.json"
4894
+ if [ ! -f "$manifest" ]; then
4895
+ echo -e "${RED}Error: Migration not found: ${migration_id}${NC}"
4896
+ echo "Run 'loki migrate --list' to see available migrations."
4897
+ return 1
4898
+ fi
4899
+
4900
+ python3 -c "
4901
+ import json, sys
4902
+ sys.path.insert(0, '.')
4903
+ from dashboard.migration_engine import MigrationPipeline
4904
+ try:
4905
+ pipeline = MigrationPipeline.load(sys.argv[1])
4906
+ progress = pipeline.get_progress()
4907
+ print(json.dumps(progress, indent=2))
4908
+ except Exception as e:
4909
+ print(f'\033[0;31mError reading migration: {e}\033[0m', file=sys.stderr)
4910
+ sys.exit(1)
4911
+ " "$migration_id" || {
4912
+ echo -e "${RED}Error reading migration manifest${NC}"
4913
+ return 1
4914
+ }
4915
+ }
4916
+
4917
+ cmd_migrate_show_plan() {
4918
+ local codebase_path="${1:-$(pwd)}"
4919
+ local migrations_dir="${HOME}/.loki/migrations"
4920
+
4921
+ # Find plan for this codebase
4922
+ local plan_file=""
4923
+ if [ -f "${codebase_path}/.loki/migration-plan.json" ]; then
4924
+ plan_file="${codebase_path}/.loki/migration-plan.json"
4925
+ else
4926
+ # Search in global migrations dir
4927
+ local latest
4928
+ latest=$(find "$migrations_dir" -name "migration-plan.json" -maxdepth 2 2>/dev/null | sort | tail -1)
4929
+ if [ -n "$latest" ]; then
4930
+ plan_file="$latest"
4931
+ fi
4932
+ fi
4933
+
4934
+ if [ -z "$plan_file" ] || [ ! -f "$plan_file" ]; then
4935
+ echo -e "${YELLOW}No migration plan found.${NC}"
4936
+ echo "Generate one with: loki migrate <path> --target <target> --plan-only"
4937
+ return 0
4938
+ fi
4939
+
4940
+ echo -e "${BOLD}Migration Plan${NC}"
4941
+ echo -e "${DIM}Source: ${plan_file}${NC}"
4942
+ echo "---"
4943
+
4944
+ # Try engine-based summary first, fall back to raw JSON display
4945
+ local migration_id_for_plan=""
4946
+ migration_id_for_plan=$(python3 -c "
4947
+ import json, sys
4948
+ with open(sys.argv[1]) as f:
4949
+ data = json.load(f)
4950
+ # Try to extract migration ID from path or data
4951
+ print(data.get('id', ''))
4952
+ " "$plan_file" 2>/dev/null || echo "")
4953
+
4954
+ if [ -n "$migration_id_for_plan" ]; then
4955
+ python3 -c "
4956
+ import sys
4957
+ sys.path.insert(0, '.')
4958
+ from dashboard.migration_engine import MigrationPipeline
4959
+ pipeline = MigrationPipeline.load(sys.argv[1])
4960
+ print(pipeline.generate_plan_summary())
4961
+ " "$migration_id_for_plan" 2>/dev/null || {
4962
+ # Fall back to basic display if engine fails
4963
+ python3 -c "
4964
+ import json, sys
4965
+ with open(sys.argv[1]) as f:
4966
+ plan = json.load(f)
4967
+ print(json.dumps(plan, indent=2))
4968
+ " "$plan_file" || echo -e "${RED}Error reading migration plan${NC}"
4969
+ }
4970
+ else
4971
+ python3 -c "
4972
+ import json, sys
4973
+ with open(sys.argv[1]) as f:
4974
+ plan = json.load(f)
4975
+ print(json.dumps(plan, indent=2))
4976
+ " "$plan_file" || {
4977
+ echo -e "${RED}Error reading migration plan${NC}"
4978
+ return 1
4979
+ }
4980
+ fi
4981
+ }
4982
+
4983
+ cmd_migrate_start() {
4984
+ local codebase_path="$1"
4985
+ local target="$2"
4986
+ local plan_only="$3"
4987
+ local phase="$4"
4988
+ local parallel="$5"
4989
+ local compliance="$6"
4990
+ local dry_run="$7"
4991
+ local resume="$8"
4992
+ local multi_repo="$9"
4993
+ local export_report="${10}"
4994
+
4995
+ local migrations_dir="${HOME}/.loki/migrations"
4996
+ local migration_id=""
4997
+
4998
+ # Check python3 availability
4999
+ if ! command -v python3 &>/dev/null; then
5000
+ echo -e "${RED}Error: python3 is required for migration${NC}"
5001
+ return 1
5002
+ fi
5003
+
5004
+ # Check for path traversal BEFORE canonicalization
5005
+ case "$codebase_path" in
5006
+ *..*)
5007
+ echo -e "${RED}Error: Path traversal not allowed in codebase path${NC}"
5008
+ return 1
5009
+ ;;
5010
+ esac
5011
+
5012
+ # Validate codebase path
5013
+ if [ ! -d "$codebase_path" ]; then
5014
+ echo -e "${RED}Error: Codebase path does not exist: ${codebase_path}${NC}"
5015
+ return 1
5016
+ fi
5017
+
5018
+ # Then canonicalize
5019
+ codebase_path=$(cd "$codebase_path" && pwd) || {
5020
+ echo -e "${RED}Error: Cannot access $codebase_path${NC}"
5021
+ return 1
5022
+ }
5023
+
5024
+ # Validate target
5025
+ if [ -z "$target" ]; then
5026
+ echo -e "${RED}Error: --target is required${NC}"
5027
+ echo "Specify the migration target (e.g. --target typescript, --target react, --target microservices)"
5028
+ echo ""
5029
+ echo "Run 'loki migrate --help' for usage."
5030
+ return 1
5031
+ fi
5032
+
5033
+ # Validate compliance preset
5034
+ if [ -n "$compliance" ]; then
5035
+ case "$compliance" in
5036
+ healthcare|fintech|government) ;;
5037
+ *)
5038
+ echo -e "${RED}Error: Invalid compliance preset: ${compliance}${NC}"
5039
+ echo "Valid presets: healthcare, fintech, government"
5040
+ return 1
5041
+ ;;
5042
+ esac
5043
+ fi
5044
+
5045
+ # Validate parallel count
5046
+ if [ -n "$parallel" ]; then
5047
+ if ! [[ "$parallel" =~ ^[0-9]+$ ]]; then
5048
+ echo -e "${RED}Error: --parallel must be a number${NC}"
5049
+ return 1
5050
+ fi
5051
+ if [ "$parallel" -lt 1 ] || [ "$parallel" -gt 10 ]; then
5052
+ echo -e "${RED}Error: --parallel must be between 1 and 10${NC}"
5053
+ return 1
5054
+ fi
5055
+ else
5056
+ parallel=4
5057
+ fi
5058
+
5059
+ # Handle resume
5060
+ if [ "$resume" = "true" ]; then
5061
+ local latest_manifest
5062
+ latest_manifest=$(find "$migrations_dir" -name "manifest.json" -maxdepth 2 2>/dev/null | \
5063
+ xargs python3 -c "
5064
+ import json, sys
5065
+ codebase = sys.argv[1]
5066
+ manifests = []
5067
+ for path in sys.argv[2:]:
5068
+ try:
5069
+ with open(path) as f:
5070
+ m = json.load(f)
5071
+ if m.get('source_path') == codebase and m.get('status') in ('paused', 'running', 'failed'):
5072
+ manifests.append(path)
5073
+ except: pass
5074
+ if manifests:
5075
+ print(manifests[-1])
5076
+ " "$codebase_path" 2>/dev/null || echo "")
5077
+
5078
+ if [ -z "$latest_manifest" ]; then
5079
+ echo -e "${RED}Error: No resumable migration found for ${codebase_path}${NC}"
5080
+ echo "Start a new migration with: loki migrate ${codebase_path} --target ${target}"
5081
+ return 1
5082
+ fi
5083
+
5084
+ migration_id=$(python3 -c "import json, sys; print(json.load(open(sys.argv[1]))['id'])" "$latest_manifest" 2>/dev/null)
5085
+ echo -e "${GREEN}Resuming migration: ${migration_id}${NC}"
5086
+ echo -e "${DIM}Loading checkpoint...${NC}"
5087
+ fi
5088
+
5089
+ # Handle multi-repo
5090
+ if [ -n "$multi_repo" ]; then
5091
+ local repo_count=0
5092
+ local repos=()
5093
+ local _repo
5094
+ # Use an array to safely handle glob expansion with spaces in paths
5095
+ local _expanded_repos=()
5096
+ # Save and restore globbing options
5097
+ local _old_nullglob=$(shopt -p nullglob 2>/dev/null || true)
5098
+ shopt -s nullglob
5099
+ local _expanded_repos=($multi_repo)
5100
+ eval "$_old_nullglob" 2>/dev/null || true
5101
+ for _repo in "${_expanded_repos[@]}"; do
5102
+ if [ -d "$_repo" ]; then
5103
+ repos+=("$_repo")
5104
+ repo_count=$((repo_count + 1))
5105
+ fi
5106
+ done
5107
+ if [ "$repo_count" -eq 0 ]; then
5108
+ echo -e "${RED}Error: No repositories found matching: ${multi_repo}${NC}"
5109
+ return 1
5110
+ fi
5111
+ echo -e "${BOLD}Multi-repo migration${NC} ($repo_count repositories)"
5112
+ echo "---"
5113
+ for repo in "${repos[@]}"; do
5114
+ echo " - $repo"
5115
+ done
5116
+ echo ""
5117
+ fi
5118
+
5119
+ # Create migration via engine
5120
+ local create_result
5121
+ create_result=$(python3 -c "
5122
+ import json, sys
5123
+ sys.path.insert(0, '.')
5124
+ from dashboard.migration_engine import MigrationPipeline
5125
+ pipeline = MigrationPipeline(sys.argv[1], sys.argv[2])
5126
+ manifest = pipeline.create_manifest()
5127
+ print(json.dumps({'id': manifest.id, 'dir': str(pipeline.migration_dir)}))
5128
+ " "$codebase_path" "$target" 2>&1) || {
5129
+ echo -e "${RED}Error: Failed to create migration${NC}"
5130
+ echo "$create_result"
5131
+ return 1
5132
+ }
5133
+ migration_id=$(echo "$create_result" | python3 -c "import json,sys; print(json.load(sys.stdin)['id'])")
5134
+ local migration_dir
5135
+ migration_dir=$(echo "$create_result" | python3 -c "import json,sys; print(json.load(sys.stdin)['dir'])")
5136
+
5137
+ # Security scan (first step of understand phase)
5138
+ echo -e "${BOLD}[Security] Scanning for secrets...${NC}"
5139
+ local secrets_found=0
5140
+ if command -v grep &>/dev/null; then
5141
+ local secret_patterns="(password|secret|api_key|apikey|token|private_key|AWS_SECRET|DB_PASS)\\s*[=:]\\s*['\"][^'\"]+['\"]"
5142
+ secrets_found=$(grep -rEli "$secret_patterns" "$codebase_path" --include='*.js' --include='*.ts' --include='*.py' --include='*.rb' --include='*.go' --include='*.java' --include='*.env' --include='*.yml' --include='*.yaml' --include='*.json' --include='*.toml' --include='*.cfg' --include='*.ini' 2>/dev/null | wc -l | tr -d ' ')
5143
+ fi
5144
+
5145
+ if [ "$secrets_found" -gt 0 ]; then
5146
+ echo -e "${RED}WARNING: Found $secrets_found file(s) potentially containing secrets${NC}"
5147
+ echo -e "${YELLOW}Review these files before migration to avoid leaking credentials.${NC}"
5148
+ echo ""
5149
+ else
5150
+ echo -e "${GREEN}No secrets detected.${NC}"
5151
+ echo ""
5152
+ fi
5153
+
5154
+ # Handle dry-run
5155
+ if [ "$dry_run" = "true" ]; then
5156
+ echo -e "${BOLD}[Dry Run] Migration preview${NC}"
5157
+ echo "---"
5158
+ echo -e " Codebase: ${codebase_path}"
5159
+ echo -e " Target: ${target}"
5160
+ echo -e " Parallel: ${parallel} agents"
5161
+ [ -n "$compliance" ] && echo -e " Compliance: ${compliance}"
5162
+ [ -n "$multi_repo" ] && echo -e " Multi-repo: ${multi_repo}"
5163
+ echo ""
5164
+ echo -e "${DIM}Phases that would execute:${NC}"
5165
+ echo " 1. understand - Analyze codebase structure and dependencies"
5166
+ echo " 2. guardrail - Set up test safety nets and rollback points"
5167
+ echo " 3. migrate - Execute migration transforms"
5168
+ echo " 4. verify - Run verification suite and regression tests"
5169
+ echo ""
5170
+ echo -e "${YELLOW}No changes were made (dry-run mode).${NC}"
5171
+ # Clean up migration dir created by engine
5172
+ rm -rf "$migration_dir" 2>/dev/null || true
5173
+ return 0
5174
+ fi
5175
+
5176
+ emit_event migration cli start "id=$migration_id" "target=$target" "source=$codebase_path" 2>/dev/null || true
5177
+
5178
+ echo -e "${BOLD}Migration: ${migration_id}${NC}"
5179
+ echo "---"
5180
+ echo -e " Codebase: ${codebase_path}"
5181
+ echo -e " Target: ${target}"
5182
+ echo -e " Parallel: ${parallel} agents"
5183
+ [ -n "$compliance" ] && echo -e " Compliance: ${compliance}"
5184
+ echo ""
5185
+
5186
+ # Determine which phases to run
5187
+ local phases_to_run=()
5188
+ if [ -n "$phase" ]; then
5189
+ case "$phase" in
5190
+ understand|guardrail|migrate|verify)
5191
+ phases_to_run=("$phase")
5192
+ ;;
5193
+ *)
5194
+ echo -e "${RED}Error: Invalid phase: ${phase}${NC}"
5195
+ echo "Valid phases: understand, guardrail, migrate, verify"
5196
+ return 1
5197
+ ;;
5198
+ esac
5199
+ elif [ "$plan_only" = "true" ]; then
5200
+ phases_to_run=("understand" "guardrail")
5201
+ else
5202
+ phases_to_run=("understand" "guardrail" "migrate" "verify")
5203
+ fi
5204
+
5205
+ # Execute phases
5206
+ for p in "${phases_to_run[@]}"; do
5207
+ echo -e "${CYAN}[Phase: ${p}]${NC} Starting..."
5208
+
5209
+ # Start phase via engine
5210
+ python3 -c "
5211
+ import sys
5212
+ sys.path.insert(0, '.')
5213
+ from dashboard.migration_engine import MigrationPipeline
5214
+ pipeline = MigrationPipeline.load(sys.argv[1])
5215
+ pipeline.start_phase(sys.argv[2])
5216
+ " "$migration_id" "$p" || {
5217
+ echo -e "${RED}Error: Failed to start phase $p${NC}"
5218
+ return 1
5219
+ }
5220
+
5221
+ # Phase-specific logic
5222
+ case "$p" in
5223
+ understand)
5224
+ echo -e " ${DIM}Analyzing codebase structure...${NC}"
5225
+ echo -e " ${DIM}Detecting languages, frameworks, dependencies...${NC}"
5226
+ echo -e " ${DIM}Building dependency graph...${NC}"
5227
+ ;;
5228
+ guardrail)
5229
+ echo -e " ${DIM}Identifying existing tests...${NC}"
5230
+ echo -e " ${DIM}Creating rollback checkpoints...${NC}"
5231
+ echo -e " ${DIM}Setting up safety nets...${NC}"
5232
+ ;;
5233
+ migrate)
5234
+ echo -e " ${DIM}Executing migration transforms (${parallel} parallel agents)...${NC}"
5235
+ echo -e " ${DIM}Applying incremental changes...${NC}"
5236
+ ;;
5237
+ verify)
5238
+ echo -e " ${DIM}Running verification suite...${NC}"
5239
+ echo -e " ${DIM}Checking regression tests...${NC}"
5240
+ echo -e " ${DIM}Validating build output...${NC}"
5241
+ ;;
5242
+ esac
5243
+
5244
+ # Complete phase via engine
5245
+ python3 -c "
5246
+ import sys
5247
+ sys.path.insert(0, '.')
5248
+ from dashboard.migration_engine import MigrationPipeline
5249
+ pipeline = MigrationPipeline.load(sys.argv[1])
5250
+ pipeline.advance_phase(sys.argv[2])
5251
+ " "$migration_id" "$p" || {
5252
+ echo -e "${RED}Error: Failed to complete phase $p${NC}"
5253
+ return 1
5254
+ }
5255
+
5256
+ echo -e "${GREEN} [Phase: ${p}] Complete${NC}"
5257
+ echo ""
5258
+ done
5259
+
5260
+ # Plan-only: generate plan file and stop
5261
+ if [ "$plan_only" = "true" ]; then
5262
+ echo -e "${BOLD}Migration plan generated.${NC}"
5263
+ echo -e "View with: loki migrate --show-plan"
5264
+
5265
+ python3 -c "
5266
+ import json, sys
5267
+ from datetime import datetime
5268
+ plan = {
5269
+ 'target': sys.argv[1],
5270
+ 'source_path': sys.argv[2],
5271
+ 'estimated_hours': '?',
5272
+ 'risk_level': 'medium',
5273
+ 'steps': [],
5274
+ 'dependencies': [],
5275
+ 'breaking_changes': [],
5276
+ 'generated_at': datetime.now().isoformat()
5277
+ }
5278
+ with open(sys.argv[3], 'w') as f:
5279
+ json.dump(plan, f, indent=2)
5280
+ " "$target" "$codebase_path" "${migration_dir}/migration-plan.json" || {
5281
+ echo -e "${RED}Error: Failed to create migration plan${NC}"
5282
+ return 1
5283
+ }
5284
+
5285
+ # Update status to paused
5286
+ python3 -c "
5287
+ import json, sys
5288
+ from datetime import datetime
5289
+ manifest_path = sys.argv[1]
5290
+ with open(manifest_path) as f:
5291
+ m = json.load(f)
5292
+ m['status'] = 'paused'
5293
+ m['updated_at'] = datetime.now().isoformat()
5294
+ with open(manifest_path, 'w') as f:
5295
+ json.dump(m, f, indent=2)
5296
+ " "${migration_dir}/manifest.json" || {
5297
+ echo -e "${RED}Error: Failed to update migration state${NC}"
5298
+ return 1
5299
+ }
5300
+ return 0
5301
+ fi
5302
+
5303
+ # Mark migration complete
5304
+ python3 -c "
5305
+ import json, sys
5306
+ from datetime import datetime
5307
+ manifest_path = sys.argv[1]
5308
+ with open(manifest_path) as f:
5309
+ m = json.load(f)
5310
+ m['status'] = 'completed'
5311
+ m['progress_pct'] = 100
5312
+ m['updated_at'] = datetime.now().isoformat()
5313
+ with open(manifest_path, 'w') as f:
5314
+ json.dump(m, f, indent=2)
5315
+ " "${migration_dir}/manifest.json" || {
5316
+ echo -e "${RED}Error: Failed to update migration state${NC}"
5317
+ return 1
5318
+ }
5319
+
5320
+ emit_event migration cli complete "id=$migration_id" "target=$target" 2>/dev/null || true
5321
+
5322
+ # Export report if requested
5323
+ if [ "$export_report" = "true" ]; then
5324
+ local report_file="${codebase_path}/migration-report-${migration_id}.json"
5325
+ cp "${migration_dir}/manifest.json" "$report_file" 2>/dev/null
5326
+ echo -e "${GREEN}Report exported: ${report_file}${NC}"
5327
+ fi
5328
+
5329
+ echo -e "${GREEN}${BOLD}Migration complete: ${migration_id}${NC}"
5330
+ echo -e "View details: loki migrate --status ${migration_id}"
5331
+ }
5332
+
5333
+ cmd_migrate() {
5334
+ local codebase_path=""
5335
+ local target=""
5336
+ local plan_only="false"
5337
+ local show_plan="false"
5338
+ local phase=""
5339
+ local parallel=""
5340
+ local compliance=""
5341
+ local dry_run="false"
5342
+ local do_resume="false"
5343
+ local multi_repo=""
5344
+ local export_report="false"
5345
+ local do_list="false"
5346
+ local do_status="false"
5347
+ local status_id=""
5348
+
5349
+ if [ $# -eq 0 ]; then
5350
+ cmd_migrate_help
5351
+ return 0
5352
+ fi
5353
+
5354
+ while [[ $# -gt 0 ]]; do
5355
+ case "$1" in
5356
+ --help|-h)
5357
+ cmd_migrate_help
5358
+ return 0
5359
+ ;;
5360
+ --list)
5361
+ do_list="true"
5362
+ shift
5363
+ ;;
5364
+ --status)
5365
+ do_status="true"
5366
+ if [[ -n "${2:-}" ]] && [[ ! "$2" =~ ^-- ]]; then
5367
+ status_id="$2"
5368
+ shift
5369
+ fi
5370
+ shift
5371
+ ;;
5372
+ --show-plan)
5373
+ show_plan="true"
5374
+ shift
5375
+ ;;
5376
+ --target)
5377
+ if [[ -z "${2:-}" ]]; then
5378
+ echo -e "${RED}Error: --target requires a value${NC}"
5379
+ return 1
5380
+ fi
5381
+ target="$2"
5382
+ shift 2
5383
+ ;;
5384
+ --target=*)
5385
+ target="${1#*=}"
5386
+ shift
5387
+ ;;
5388
+ --plan-only)
5389
+ plan_only="true"
5390
+ shift
5391
+ ;;
5392
+ --phase)
5393
+ if [[ -z "${2:-}" ]]; then
5394
+ echo -e "${RED}Error: --phase requires a value${NC}"
5395
+ return 1
5396
+ fi
5397
+ phase="$2"
5398
+ shift 2
5399
+ ;;
5400
+ --phase=*)
5401
+ phase="${1#*=}"
5402
+ shift
5403
+ ;;
5404
+ --parallel)
5405
+ if [[ -z "${2:-}" ]]; then
5406
+ echo -e "${RED}Error: --parallel requires a value${NC}"
5407
+ return 1
5408
+ fi
5409
+ parallel="$2"
5410
+ shift 2
5411
+ ;;
5412
+ --parallel=*)
5413
+ parallel="${1#*=}"
5414
+ shift
5415
+ ;;
5416
+ --compliance)
5417
+ if [[ -z "${2:-}" ]]; then
5418
+ echo -e "${RED}Error: --compliance requires a value${NC}"
5419
+ return 1
5420
+ fi
5421
+ compliance="$2"
5422
+ shift 2
5423
+ ;;
5424
+ --compliance=*)
5425
+ compliance="${1#*=}"
5426
+ shift
5427
+ ;;
5428
+ --dry-run)
5429
+ dry_run="true"
5430
+ shift
5431
+ ;;
5432
+ --resume)
5433
+ do_resume="true"
5434
+ shift
5435
+ ;;
5436
+ --multi-repo)
5437
+ if [[ -z "${2:-}" ]]; then
5438
+ echo -e "${RED}Error: --multi-repo requires a value${NC}"
5439
+ return 1
5440
+ fi
5441
+ multi_repo="$2"
5442
+ shift 2
5443
+ ;;
5444
+ --multi-repo=*)
5445
+ multi_repo="${1#*=}"
5446
+ shift
5447
+ ;;
5448
+ --export-report)
5449
+ export_report="true"
5450
+ shift
5451
+ ;;
5452
+ -*)
5453
+ echo -e "${RED}Unknown option: $1${NC}"
5454
+ echo "Run 'loki migrate --help' for usage."
5455
+ return 1
5456
+ ;;
5457
+ *)
5458
+ if [ -z "$codebase_path" ]; then
5459
+ codebase_path="$1"
5460
+ else
5461
+ echo -e "${RED}Error: Unexpected argument: $1${NC}"
5462
+ echo "Run 'loki migrate --help' for usage."
5463
+ return 1
5464
+ fi
5465
+ shift
5466
+ ;;
5467
+ esac
5468
+ done
5469
+
5470
+ # Route to subcommands
5471
+ if [ "$do_list" = "true" ]; then
5472
+ cmd_migrate_list
5473
+ return 0
5474
+ fi
5475
+
5476
+ if [ "$do_status" = "true" ]; then
5477
+ cmd_migrate_status "$status_id"
5478
+ return 0
5479
+ fi
5480
+
5481
+ if [ "$show_plan" = "true" ]; then
5482
+ cmd_migrate_show_plan "${codebase_path:-$(pwd)}"
5483
+ return 0
5484
+ fi
5485
+
5486
+ # Default: start or continue migration
5487
+ if [ -z "$codebase_path" ]; then
5488
+ echo -e "${RED}Error: Codebase path is required${NC}"
5489
+ echo "Usage: loki migrate <path-to-codebase> --target <target>"
5490
+ echo ""
5491
+ echo "Run 'loki migrate --help' for usage."
5492
+ return 1
5493
+ fi
5494
+
5495
+ cmd_migrate_start "$codebase_path" "$target" "$plan_only" "$phase" "$parallel" "$compliance" "$dry_run" "$do_resume" "$multi_repo" "$export_report"
5496
+ }
5497
+
4691
5498
  # Main command dispatcher
4692
5499
  main() {
4693
5500
  if [ $# -eq 0 ]; then
@@ -4803,6 +5610,12 @@ main() {
4803
5610
  audit)
4804
5611
  cmd_audit "$@"
4805
5612
  ;;
5613
+ optimize)
5614
+ cmd_optimize "$@"
5615
+ ;;
5616
+ migrate)
5617
+ cmd_migrate "$@"
5618
+ ;;
4806
5619
  metrics)
4807
5620
  cmd_metrics "$@"
4808
5621
  ;;
@@ -4826,7 +5639,7 @@ main() {
4826
5639
  esac
4827
5640
  }
4828
5641
 
4829
- # Agent action audit log
5642
+ # Agent action audit log and quality scanning
4830
5643
  cmd_audit() {
4831
5644
  local subcommand="${1:-help}"
4832
5645
  local audit_file="$LOKI_DIR/logs/agent-audit.jsonl"
@@ -4885,16 +5698,138 @@ print(f' {\"TOTAL\":25s} {sum(counts.values())}')
4885
5698
  echo " python3 required for count summary"
4886
5699
  fi
4887
5700
  ;;
5701
+ scan)
5702
+ shift
5703
+ local preset="default"
5704
+ local do_export=""
5705
+
5706
+ while [[ $# -gt 0 ]]; do
5707
+ case "$1" in
5708
+ --preset) if [[ -z "${2:-}" ]]; then echo -e "${RED}Error: --preset requires a value${NC}"; exit 1; fi; preset="$2"; shift 2 ;;
5709
+ --preset=*) preset="${1#*=}"; shift ;;
5710
+ --export) do_export="true"; shift ;;
5711
+ --help|-h)
5712
+ echo -e "${BOLD}loki audit scan${NC} - Run quality scan"
5713
+ echo ""
5714
+ echo "Usage: loki audit scan [options]"
5715
+ echo ""
5716
+ echo "Options:"
5717
+ echo " --preset NAME Compliance preset (default|healthcare|fintech|government)"
5718
+ echo " --export Save report to .loki/quality/report-{date}.json"
5719
+ echo ""
5720
+ exit 0
5721
+ ;;
5722
+ *) echo -e "${RED}Unknown option: $1${NC}"; exit 1 ;;
5723
+ esac
5724
+ done
5725
+
5726
+ case "$preset" in
5727
+ default|healthcare|fintech|government) ;;
5728
+ *) echo -e "${RED}Error: Invalid preset '$preset'. Must be one of: default, healthcare, fintech, government${NC}"; exit 1 ;;
5729
+ esac
5730
+
5731
+ local port="${LOKI_DASHBOARD_PORT:-57374}"
5732
+ local host="127.0.0.1"
5733
+ local url="http://${host}:${port}/api/quality-scan?preset=${preset}"
5734
+
5735
+ echo -e "${BOLD}Running quality scan...${NC} (preset: $preset)"
5736
+ echo ""
5737
+
5738
+ local response http_code
5739
+ response=$(curl -s -w "\n%{http_code}" -X POST "$url" 2>/dev/null) || true
5740
+ http_code=$(echo "$response" | tail -1)
5741
+ response=$(echo "$response" | sed '$d')
5742
+ if [ -z "$http_code" ] || [ "$http_code" = "000" ]; then
5743
+ echo -e "${RED}Error: Could not connect to dashboard API at http://${host}:${port}${NC}"
5744
+ echo "Make sure the dashboard is running: loki serve"
5745
+ exit 1
5746
+ fi
5747
+ if [ "$http_code" -ge 400 ] 2>/dev/null; then
5748
+ echo -e "${RED}Error: Dashboard API returned HTTP $http_code${NC}"
5749
+ [ -n "$response" ] && echo "$response"
5750
+ exit 1
5751
+ fi
5752
+
5753
+ if ! command -v python3 &>/dev/null; then
5754
+ echo "$response" | jq . 2>/dev/null || echo "$response"
5755
+ else
5756
+ echo "$response" | python3 -c "
5757
+ import json, sys
5758
+ data = json.loads(sys.stdin.read())
5759
+
5760
+ score = data.get('score', 0)
5761
+ grade = data.get('grade', '?')
5762
+ print(f'Quality Score: {score}/100 Grade: {grade}')
5763
+ print('---')
5764
+
5765
+ # Category scores
5766
+ categories = data.get('categories', {})
5767
+ if categories:
5768
+ print()
5769
+ print('Category Scores:')
5770
+ for cat, cat_score in sorted(categories.items()):
5771
+ print(f' {cat:20s} {cat_score}/100')
5772
+
5773
+ # Findings by severity
5774
+ findings = data.get('findings', [])
5775
+ if findings:
5776
+ print()
5777
+ print('Findings:')
5778
+ for f in findings:
5779
+ sev = f.get('severity', 'info')
5780
+ msg = f.get('message', '')
5781
+ cat = f.get('category', '')
5782
+ if sev == 'critical':
5783
+ print(f' \033[0;31m[CRITICAL]\033[0m {cat}: {msg}')
5784
+ elif sev == 'major':
5785
+ print(f' \033[1;33m[MAJOR]\033[0m {cat}: {msg}')
5786
+ else:
5787
+ print(f' [MINOR] {cat}: {msg}')
5788
+ print()
5789
+ " 2>/dev/null || echo "$response"
5790
+ fi
5791
+
5792
+ # Export report if requested
5793
+ if [ -n "$do_export" ]; then
5794
+ local report_dir="$LOKI_DIR/quality"
5795
+ mkdir -p "$report_dir"
5796
+ local date_str
5797
+ date_str=$(date +%Y-%m-%d)
5798
+ local report_file="$report_dir/report-${date_str}.json"
5799
+
5800
+ local report_url="http://${host}:${port}/api/quality-report?format=json"
5801
+ local report_data
5802
+ report_data=$(curl -sf "$report_url" 2>/dev/null) || true
5803
+ if [ -n "$report_data" ]; then
5804
+ echo "$report_data" > "$report_file"
5805
+ echo -e "${GREEN}Report exported to $report_file${NC}"
5806
+ else
5807
+ # Fall back to scan response
5808
+ echo "$response" > "$report_file"
5809
+ echo -e "${GREEN}Report exported to $report_file${NC}"
5810
+ fi
5811
+ fi
5812
+ ;;
5813
+ --preset|--export)
5814
+ # Handle flags passed directly to 'loki audit' (shortcut for 'loki audit scan')
5815
+ cmd_audit scan "$@"
5816
+ return
5817
+ ;;
4888
5818
  --help|-h|help)
4889
- echo -e "${BOLD}loki audit${NC} - Agent action audit log"
5819
+ echo -e "${BOLD}loki audit${NC} - Agent audit log and quality scanning"
4890
5820
  echo ""
4891
- echo "Usage: loki audit <subcommand>"
5821
+ echo "Usage: loki audit <subcommand> [options]"
4892
5822
  echo ""
4893
5823
  echo "Subcommands:"
4894
5824
  echo " log [N] Show last N audit log entries (default: 50)"
4895
5825
  echo " count Count actions by type"
5826
+ echo " scan Run quality scan against dashboard API"
4896
5827
  echo " help Show this help"
4897
5828
  echo ""
5829
+ echo "Quality Scan Options (loki audit scan):"
5830
+ echo " --preset NAME Compliance preset (default|healthcare|fintech|government)"
5831
+ echo " --export Save report to .loki/quality/report-{date}.json"
5832
+ echo ""
4898
5833
  echo "The agent audit log records actions taken during Loki sessions,"
4899
5834
  echo "including CLI invocations, git commits, and session lifecycle events."
4900
5835
  echo "Log file: $audit_file"