loki-mode 7.5.17 → 7.5.28

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.
Files changed (47) hide show
  1. package/README.md +10 -9
  2. package/SKILL.md +14 -14
  3. package/VERSION +1 -1
  4. package/autonomy/completion-council.sh +26 -3
  5. package/autonomy/lib/claude-flags.sh +132 -0
  6. package/autonomy/lib/mcp-config.sh +160 -0
  7. package/autonomy/lib/project-graph.sh +685 -0
  8. package/autonomy/lib/voter-agents.sh +356 -0
  9. package/autonomy/loki +108 -111
  10. package/autonomy/run.sh +95 -186
  11. package/bin/loki +12 -1
  12. package/dashboard/__init__.py +1 -1
  13. package/dashboard/requirements.txt +13 -8
  14. package/dashboard/server.py +33 -15
  15. package/dashboard/static/index.html +298 -299
  16. package/docs/INSTALLATION.md +54 -21
  17. package/docs/retrospectives/v7.5.15-fleet-postmortem.md +325 -0
  18. package/docs/retrospectives/v7.5.15-honesty-audit.md +136 -0
  19. package/docs/retrospectives/v7.5.15-llm-failure-modes.md +49 -0
  20. package/loki-ts/data/finding-schema.json +74 -0
  21. package/loki-ts/data/model-pricing.json +12 -0
  22. package/loki-ts/dist/loki.js +198 -172
  23. package/mcp/__init__.py +1 -1
  24. package/mcp/lsp_proxy.py +713 -0
  25. package/mcp/requirements.txt +9 -3
  26. package/mcp/tests/__init__.py +0 -0
  27. package/mcp/tests/test_lsp_proxy.py +377 -0
  28. package/memory/app_graph.py +153 -0
  29. package/memory/storage.py +6 -1
  30. package/memory/tests/test_app_graph.py +134 -0
  31. package/package.json +4 -3
  32. package/providers/claude.sh +115 -4
  33. package/providers/codex.sh +2 -2
  34. package/providers/loader.sh +4 -4
  35. package/providers/model_catalog.json +0 -9
  36. package/providers/models.sh +1 -2
  37. package/references/multi-provider.md +26 -35
  38. package/references/prompt-repetition.md +1 -1
  39. package/references/quality-control.md +1 -1
  40. package/skills/00-index.md +3 -3
  41. package/skills/model-selection.md +11 -14
  42. package/skills/providers.md +17 -57
  43. package/skills/quality-gates.md +2 -2
  44. package/skills/troubleshooting.md +1 -1
  45. package/src/integrations/github/action-handler.js +3 -2
  46. package/src/protocols/tools/start-project.js +1 -1
  47. package/providers/gemini.sh +0 -343
@@ -810,7 +810,7 @@ async def agent_card() -> dict:
810
810
  "agents": 41,
811
811
  "swarms": 8,
812
812
  "quality_gates": 9,
813
- "providers": ["claude", "codex", "gemini", "cline", "aider"],
813
+ "providers": ["claude", "codex", "cline", "aider"],
814
814
  "streaming": True,
815
815
  "pushNotifications": False,
816
816
  "stateTransitionHistory": True,
@@ -3168,8 +3168,17 @@ def _parse_time_range(time_range: str) -> Optional[datetime]:
3168
3168
  return datetime.now(timezone.utc) - delta
3169
3169
 
3170
3170
 
3171
- def _read_events(time_range: str = "7d", max_events: int = 10000) -> list:
3172
- """Read events from .loki/events.jsonl with time filter and size limits."""
3171
+ def _read_events(time_range: str = "7d", max_events: int = 10000, type_prefix: Optional[str] = None) -> list:
3172
+ """Read events from .loki/events.jsonl with time filter and size limits.
3173
+
3174
+ Args:
3175
+ time_range: e.g. "7d", "24h", "30m". Events older than the cutoff are dropped.
3176
+ max_events: hard cap on the number of returned events.
3177
+ type_prefix: when set (non-empty), only return events whose ``type`` field
3178
+ starts with this prefix. Backward compatible: when None or empty,
3179
+ no type filtering is applied. Used by v7.5.22 Phase D for filtering
3180
+ ``claude_hook_*`` events without adding a new endpoint.
3181
+ """
3173
3182
  events_file = _get_loki_dir() / "events.jsonl"
3174
3183
  if not events_file.exists():
3175
3184
  return []
@@ -3208,6 +3217,10 @@ def _read_events(time_range: str = "7d", max_events: int = 10000) -> list:
3208
3217
  continue
3209
3218
  except (ValueError, TypeError):
3210
3219
  pass # Keep events with unparseable timestamps
3220
+ # Optional type-prefix filter (v7.5.22 Phase D).
3221
+ if type_prefix:
3222
+ if not str(event.get("type", "")).startswith(type_prefix):
3223
+ continue
3211
3224
  events.append(event)
3212
3225
  except json.JSONDecodeError:
3213
3226
  pass
@@ -3401,9 +3414,6 @@ _DEFAULT_PRICING = {
3401
3414
  "haiku": {"input": 1.00, "output": 5.00},
3402
3415
  # OpenAI Codex
3403
3416
  "gpt-5.3-codex": {"input": 1.50, "output": 12.00},
3404
- # Google Gemini
3405
- "gemini-3-pro": {"input": 1.25, "output": 10.00},
3406
- "gemini-3-flash": {"input": 0.10, "output": 0.40},
3407
3417
  }
3408
3418
 
3409
3419
  # Active pricing - starts with defaults, updated from .loki/pricing.json
@@ -3616,8 +3626,6 @@ _PROVIDER_LABELS = {
3616
3626
  "sonnet": "Sonnet 4.5",
3617
3627
  "haiku": "Haiku 4.5",
3618
3628
  "gpt-5.3-codex": "GPT-5.3 Codex",
3619
- "gemini-3-pro": "Gemini 3 Pro",
3620
- "gemini-3-flash": "Gemini 3 Flash",
3621
3629
  }
3622
3630
 
3623
3631
  _MODEL_PROVIDERS = {
@@ -3625,8 +3633,6 @@ _MODEL_PROVIDERS = {
3625
3633
  "sonnet": "claude",
3626
3634
  "haiku": "claude",
3627
3635
  "gpt-5.3-codex": "codex",
3628
- "gemini-3-pro": "gemini",
3629
- "gemini-3-flash": "gemini",
3630
3636
  "cline-default": "cline",
3631
3637
  "aider-default": "aider",
3632
3638
  }
@@ -3787,13 +3793,18 @@ async def get_council_transcripts(
3787
3793
  limit: int = Query(default=20, ge=1, le=200),
3788
3794
  since: Optional[str] = Query(default=None),
3789
3795
  iter_min: Optional[int] = Query(default=None, ge=0),
3796
+ type_prefix: Optional[str] = Query(default=None),
3790
3797
  ):
3791
3798
  """List council transcript records, sorted descending by iteration number.
3792
3799
 
3793
3800
  Query params:
3794
- limit int, default=20, max=200
3795
- since ISO8601 string (optional), filter to transcripts after this time
3796
- iter_min int (optional), filter to iteration >= N
3801
+ limit int, default=20, max=200
3802
+ since ISO8601 string (optional), filter to transcripts after this time
3803
+ iter_min int (optional), filter to iteration >= N
3804
+ type_prefix str (optional), v7.5.22 Phase D. When set, the response also
3805
+ includes a ``hook_events`` array of matching .loki/events.jsonl
3806
+ entries whose ``type`` starts with this prefix (e.g.
3807
+ ``claude_hook_``). Unset -> behavior unchanged.
3797
3808
  """
3798
3809
  # Validate query params before any early-return so invalid inputs always get 400.
3799
3810
  since_dt = None
@@ -3805,7 +3816,10 @@ async def get_council_transcripts(
3805
3816
 
3806
3817
  transcripts_dir = _get_loki_dir() / "council" / "transcripts"
3807
3818
  if not transcripts_dir.exists():
3808
- return {"transcripts": [], "total": 0, "latest_id": None}
3819
+ response: dict = {"transcripts": [], "total": 0, "latest_id": None}
3820
+ if type_prefix:
3821
+ response["hook_events"] = _read_events(type_prefix=type_prefix)
3822
+ return response
3809
3823
 
3810
3824
  records = []
3811
3825
  for f in sorted(transcripts_dir.glob("iter-*.json"), reverse=True):
@@ -3834,11 +3848,15 @@ async def get_council_transcripts(
3834
3848
  if len(records) >= limit:
3835
3849
  break
3836
3850
 
3837
- return {
3851
+ response = {
3838
3852
  "transcripts": records,
3839
3853
  "total": len(records),
3840
3854
  "latest_id": records[0].get("iteration_id") if records else None,
3841
3855
  }
3856
+ # v7.5.22 Phase D: opt-in hook-event passthrough via _read_events filter.
3857
+ if type_prefix:
3858
+ response["hook_events"] = _read_events(type_prefix=type_prefix)
3859
+ return response
3842
3860
 
3843
3861
 
3844
3862
  @app.get("/api/council/transcripts/{iteration_id}")