loki-mode 6.73.1 → 6.74.1
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/LICENSE +2 -0
- package/SKILL.md +8 -4
- package/VERSION +1 -1
- package/dashboard/__init__.py +1 -1
- package/dashboard/server.py +247 -1
- package/docs/INSTALLATION.md +1 -1
- package/mcp/__init__.py +1 -1
- package/package.json +1 -1
- package/web-app/dist/assets/{AdminPage-iWZB_xo6.js → AdminPage-DSVmBtfU.js} +2 -2
- package/web-app/dist/assets/Avatar-iQomSLqm.js +6 -0
- package/web-app/dist/assets/{Badge-7_-AUQsz.js → Badge-CRQf9raK.js} +1 -1
- package/web-app/dist/assets/{Button-C0spb1Uw.js → Button-6Zk1L1cC.js} +1 -1
- package/web-app/dist/assets/{ComparePage-DbS1sOwZ.js → ComparePage-CAKioZhP.js} +1 -1
- package/web-app/dist/assets/GitHubIssuesPanel-Bb_2EF_6.js +17 -0
- package/web-app/dist/assets/GitHubPRsPanel-DYOecXRG.js +17 -0
- package/web-app/dist/assets/HomePage-DlSguM1Q.js +28 -0
- package/web-app/dist/assets/{LoginPage-DAvTqpCV.js → LoginPage-D9XLoEDY.js} +1 -1
- package/web-app/dist/assets/{MetricsPage-na-RTWaj.js → MetricsPage-83qdwlaU.js} +1 -1
- package/web-app/dist/assets/NotFoundPage-NluBAEO7.js +1 -0
- package/web-app/dist/assets/ProjectPage-CDA2ae03.js +287 -0
- package/web-app/dist/assets/{ProjectsPage-gQyc9LU9.js → ProjectsPage-D-jr3x9O.js} +1 -1
- package/web-app/dist/assets/{SettingsPage-bMY5uKwO.js → SettingsPage-DpbxZSt5.js} +1 -1
- package/web-app/dist/assets/{ShowcasePage-C05_1W29.js → ShowcasePage-D-kDpbLm.js} +1 -1
- package/web-app/dist/assets/{SystemSettingsPage-D1tMDxIN.js → SystemSettingsPage-GqkBfeIX.js} +1 -1
- package/web-app/dist/assets/{TeamsPage-D-dlvdrK.js → TeamsPage-Cq0qdHn2.js} +2 -2
- package/web-app/dist/assets/{TemplatesPage-_zJFBcbN.js → TemplatesPage-BfMR3aIm.js} +1 -1
- package/web-app/dist/assets/{TerminalOutput-tm07J4dD.js → TerminalOutput-CrRPhsRz.js} +2 -2
- package/web-app/dist/assets/{activity-DicKfzsP.js → activity-C-_9ghb5.js} +1 -1
- package/web-app/dist/assets/{bell-BFjvQnJx.js → bell-B_GMuNpB.js} +1 -1
- package/web-app/dist/assets/{bot-B35Xf30p.js → bot-aZr-7umF.js} +1 -1
- package/web-app/dist/assets/{check-Ck2kcsO2.js → check-D6wFq8bk.js} +1 -1
- package/web-app/dist/assets/{chevron-left-BlMYWHUT.js → chevron-left-BNnuWY4z.js} +1 -1
- package/web-app/dist/assets/{circle-alert-BgoWCgi3.js → circle-alert-CnP3jeCc.js} +1 -1
- package/web-app/dist/assets/{clock-8-8I4vDX.js → clock-ClgakR4Z.js} +1 -1
- package/web-app/dist/assets/{cloud-DIxBvxak.js → cloud-D0xieZg5.js} +1 -1
- package/web-app/dist/assets/{copy-D3bp38SQ.js → copy-C285R_fX.js} +1 -1
- package/web-app/dist/assets/{database-WnB0jRbx.js → database-mdGcS39f.js} +1 -1
- package/web-app/dist/assets/{dollar-sign-DdIr6uXn.js → dollar-sign-BC6TADZT.js} +1 -1
- package/web-app/dist/assets/{file-code-corner-CYvOV3oD.js → file-code-corner-B1p5CnHA.js} +1 -1
- package/web-app/dist/assets/{file-plus-nPF3UxIN.js → file-plus-BSk4yJzf.js} +1 -1
- package/web-app/dist/assets/{folder-open-DjWfr--L.js → folder-open-B7QbzD3h.js} +1 -1
- package/web-app/dist/assets/{git-commit-horizontal-BhMiJhih.js → git-commit-horizontal-EX05JMQ0.js} +1 -1
- package/web-app/dist/assets/{globe-BmiZUUW8.js → globe-D3hBe7DD.js} +1 -1
- package/web-app/dist/assets/{hammer-DbUBDETj.js → hammer-D2PC2fIG.js} +1 -1
- package/web-app/dist/assets/index-CVM4A1Fw.css +1 -0
- package/web-app/dist/assets/{index-rTnHmRAz.js → index-E5sBU86N.js} +76 -76
- package/web-app/dist/assets/{layers-Ci_g9-gn.js → layers-a282sv4e.js} +1 -1
- package/web-app/dist/assets/{lightbulb-Cj7GjfmO.js → lightbulb-C5hiAWsm.js} +1 -1
- package/web-app/dist/assets/{loader-circle-aOSrwU8R.js → loader-circle-Ci-OWEEc.js} +1 -1
- package/web-app/dist/assets/{lock-Dhltj_XS.js → lock-BbcHkL-_.js} +1 -1
- package/web-app/dist/assets/{mail-CtlZ9yw2.js → mail-Zom9mgsv.js} +1 -1
- package/web-app/dist/assets/{package-B1_yf5pm.js → package-DSEab8Te.js} +1 -1
- package/web-app/dist/assets/{plus-CRPZWClI.js → plus-D5MQ_Vkt.js} +1 -1
- package/web-app/dist/assets/{refresh-cw-CghmSSTV.js → refresh-cw-CG_nDxiH.js} +1 -1
- package/web-app/dist/assets/{rotate-ccw-BmzS2O9R.js → rotate-ccw-agat414Q.js} +1 -1
- package/web-app/dist/assets/{save-B4b5vDLE.js → save-C4RFt-bD.js} +1 -1
- package/web-app/dist/assets/{server-C0JT7EJD.js → server-D_AeO3vG.js} +1 -1
- package/web-app/dist/assets/{shield-alert-DJHtTwb_.js → shield-alert-Da7Bj9HC.js} +1 -1
- package/web-app/dist/assets/{trash-2-B0AnvXQh.js → trash-2-S4CiRzBK.js} +1 -1
- package/web-app/dist/assets/{trending-down-Dc8zUzA-.js → trending-down-8qM2V_wO.js} +1 -1
- package/web-app/dist/assets/{trending-up-DkfQ5KmN.js → trending-up-DVLalru7.js} +1 -1
- package/web-app/dist/assets/{usePolling-q5-TS-ML.js → usePolling-DxBJjX_P.js} +1 -1
- package/web-app/dist/assets/user-Dmxx5pWF.js +6 -0
- package/web-app/dist/index.html +2 -2
- package/web-app/server.py +1248 -0
- package/web-app/dist/assets/Avatar-BbMCzgGt.js +0 -11
- package/web-app/dist/assets/HomePage-784kkdTZ.js +0 -28
- package/web-app/dist/assets/NotFoundPage-lcZpPG2U.js +0 -1
- package/web-app/dist/assets/ProjectPage-DQSwA6aT.js +0 -265
- package/web-app/dist/assets/index-PKxNfesE.css +0 -1
package/LICENSE
CHANGED
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.
|
|
6
|
+
# Loki Mode v6.74.1
|
|
7
7
|
|
|
8
8
|
**You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
|
|
9
9
|
|
|
@@ -21,7 +21,7 @@ Execute these steps IN ORDER at the start of EVERY turn:
|
|
|
21
21
|
- Load 1-2 modules matching your current phase
|
|
22
22
|
- Register session: Write .loki/session.json with:
|
|
23
23
|
{"pid": null, "startedAt": "<ISO timestamp>", "provider": "<provider>",
|
|
24
|
-
"invokedVia": "skill", "status": "running"}
|
|
24
|
+
"invokedVia": "skill", "status": "running", "updatedAt": "<ISO timestamp>"}
|
|
25
25
|
|
|
26
26
|
2. Read .loki/state/orchestrator.json
|
|
27
27
|
- Extract: currentPhase, tasksCompleted, tasksFailed
|
|
@@ -32,6 +32,10 @@ Execute these steps IN ORDER at the start of EVERY turn:
|
|
|
32
32
|
|
|
33
33
|
4. Check .loki/PAUSE - IF exists: Stop work, wait for removal.
|
|
34
34
|
Check .loki/STOP - IF exists: End session, update session.json status to "stopped".
|
|
35
|
+
|
|
36
|
+
5. EVERY TURN: Update .loki/session.json "updatedAt" field to current ISO timestamp.
|
|
37
|
+
This keeps the dashboard aware the skill session is alive. Sessions without
|
|
38
|
+
an update in 5 minutes are treated as stale/stopped by the dashboard.
|
|
35
39
|
```
|
|
36
40
|
|
|
37
41
|
---
|
|
@@ -137,7 +141,7 @@ GROWTH ──[continuous improvement loop]──> GROWTH
|
|
|
137
141
|
|
|
138
142
|
| File | Read | Write |
|
|
139
143
|
|------|------|-------|
|
|
140
|
-
| `.loki/session.json` | Session start | Session start (register), session end (
|
|
144
|
+
| `.loki/session.json` | Session start | Session start (register), every turn (updatedAt), session end (status) |
|
|
141
145
|
| `.loki/state/orchestrator.json` | Every turn | On phase change |
|
|
142
146
|
| `.loki/queue/pending.json` | Every turn | When claiming/completing tasks |
|
|
143
147
|
| `.loki/queue/current-task.json` | Before each ACT | When claiming task |
|
|
@@ -268,4 +272,4 @@ The following features are documented in skill modules but not yet fully automat
|
|
|
268
272
|
| Quality gates 3-reviewer system | Implemented (v5.35.0) | 5 specialist reviewers in `skills/quality-gates.md`; execution in run.sh |
|
|
269
273
|
| Benchmarks (HumanEval, SWE-bench) | Infrastructure only | Runner scripts and datasets exist in `benchmarks/`; no published results |
|
|
270
274
|
|
|
271
|
-
**v6.
|
|
275
|
+
**v6.74.1 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
6.
|
|
1
|
+
6.74.1
|
package/dashboard/__init__.py
CHANGED
package/dashboard/server.py
CHANGED
|
@@ -345,8 +345,12 @@ async def _push_loki_state_loop() -> None:
|
|
|
345
345
|
|
|
346
346
|
Reads dashboard-state.json every 2s when running (30s when idle) and
|
|
347
347
|
broadcasts a state_update message so clients don't rely solely on polling.
|
|
348
|
+
|
|
349
|
+
When dashboard-state.json is absent (skill-invoked sessions), reads state
|
|
350
|
+
from session.json + orchestrator.json + queue files instead.
|
|
348
351
|
"""
|
|
349
352
|
last_mtime: float = 0.0
|
|
353
|
+
_last_skill_hash: str = "" # Track skill-session state changes
|
|
350
354
|
while True:
|
|
351
355
|
try:
|
|
352
356
|
if not manager.active_connections:
|
|
@@ -355,6 +359,9 @@ async def _push_loki_state_loop() -> None:
|
|
|
355
359
|
|
|
356
360
|
loki_dir = _get_loki_dir()
|
|
357
361
|
state_file = loki_dir / "dashboard-state.json"
|
|
362
|
+
_session_file = loki_dir / "session.json"
|
|
363
|
+
|
|
364
|
+
_broadcast_sent = False
|
|
358
365
|
|
|
359
366
|
if state_file.exists():
|
|
360
367
|
try:
|
|
@@ -397,6 +404,15 @@ async def _push_loki_state_loop() -> None:
|
|
|
397
404
|
except (ValueError, OSError, ProcessLookupError):
|
|
398
405
|
pass
|
|
399
406
|
|
|
407
|
+
# Also check session.json for skill sessions
|
|
408
|
+
if not _pid_alive and _session_file.exists():
|
|
409
|
+
try:
|
|
410
|
+
_sd = _safe_json_read(_session_file, {})
|
|
411
|
+
if _sd.get("status") == "running":
|
|
412
|
+
_pid_alive = True
|
|
413
|
+
except (json.JSONDecodeError, KeyError):
|
|
414
|
+
pass
|
|
415
|
+
|
|
400
416
|
status_str = raw.get("mode", "autonomous")
|
|
401
417
|
if not _pid_alive:
|
|
402
418
|
status_str = "stopped"
|
|
@@ -423,9 +439,128 @@ async def _push_loki_state_loop() -> None:
|
|
|
423
439
|
"type": "status_update",
|
|
424
440
|
"data": payload,
|
|
425
441
|
})
|
|
442
|
+
_broadcast_sent = True
|
|
426
443
|
except (json.JSONDecodeError, OSError, KeyError):
|
|
427
444
|
pass
|
|
428
445
|
|
|
446
|
+
# Skill-session fallback: when dashboard-state.json is missing,
|
|
447
|
+
# read state from session.json + orchestrator.json + queue files
|
|
448
|
+
if not _broadcast_sent and _session_file.exists():
|
|
449
|
+
try:
|
|
450
|
+
_sd = _safe_json_read(_session_file, {})
|
|
451
|
+
if _sd.get("status") == "running":
|
|
452
|
+
# Validate freshness (5 min staleness threshold)
|
|
453
|
+
_sk_ts = _sd.get("updatedAt") or _sd.get("startedAt", "")
|
|
454
|
+
_sk_fresh = True
|
|
455
|
+
if _sk_ts:
|
|
456
|
+
try:
|
|
457
|
+
_sk_dt = datetime.fromisoformat(
|
|
458
|
+
_sk_ts.replace("Z", "+00:00")
|
|
459
|
+
)
|
|
460
|
+
if _sk_dt.tzinfo is None:
|
|
461
|
+
_sk_dt = _sk_dt.replace(tzinfo=timezone.utc)
|
|
462
|
+
if (datetime.now(timezone.utc) - _sk_dt).total_seconds() > 300:
|
|
463
|
+
_sk_fresh = False
|
|
464
|
+
except (ValueError, AttributeError):
|
|
465
|
+
pass
|
|
466
|
+
else:
|
|
467
|
+
try:
|
|
468
|
+
if time.time() - _session_file.stat().st_mtime > 300:
|
|
469
|
+
_sk_fresh = False
|
|
470
|
+
except OSError:
|
|
471
|
+
pass
|
|
472
|
+
|
|
473
|
+
if _sk_fresh:
|
|
474
|
+
# Read version from VERSION file
|
|
475
|
+
_sk_version = ""
|
|
476
|
+
_vf = _Path(os.path.dirname(os.path.dirname(__file__))) / "VERSION"
|
|
477
|
+
if _vf.is_file():
|
|
478
|
+
try:
|
|
479
|
+
_sk_version = _vf.read_text().strip()
|
|
480
|
+
except OSError:
|
|
481
|
+
pass
|
|
482
|
+
|
|
483
|
+
# Read orchestrator state
|
|
484
|
+
_sk_phase = ""
|
|
485
|
+
_sk_iteration = 0
|
|
486
|
+
_sk_complexity = "standard"
|
|
487
|
+
_orch_f = loki_dir / "state" / "orchestrator.json"
|
|
488
|
+
if _orch_f.exists():
|
|
489
|
+
try:
|
|
490
|
+
_orch = _safe_json_read(_orch_f, {})
|
|
491
|
+
_sk_phase = _orch.get("currentPhase", "") or ""
|
|
492
|
+
_sk_iteration = _orch.get("iteration", 0)
|
|
493
|
+
_sk_complexity = _orch.get("complexity", "standard") or "standard"
|
|
494
|
+
except (json.JSONDecodeError, KeyError):
|
|
495
|
+
pass
|
|
496
|
+
|
|
497
|
+
# Read pending tasks
|
|
498
|
+
_sk_pending = 0
|
|
499
|
+
_sk_current_task = ""
|
|
500
|
+
_pf = loki_dir / "queue" / "pending.json"
|
|
501
|
+
if _pf.exists():
|
|
502
|
+
try:
|
|
503
|
+
_pd = _safe_json_read(_pf, [])
|
|
504
|
+
_pt = _pd.get("tasks", _pd) if isinstance(_pd, dict) else _pd
|
|
505
|
+
if isinstance(_pt, list):
|
|
506
|
+
_sk_pending = len(_pt)
|
|
507
|
+
except (json.JSONDecodeError, KeyError, AttributeError):
|
|
508
|
+
pass
|
|
509
|
+
|
|
510
|
+
_ipf = loki_dir / "queue" / "in-progress.json"
|
|
511
|
+
if _ipf.exists():
|
|
512
|
+
try:
|
|
513
|
+
_ipd = _safe_json_read(_ipf, [])
|
|
514
|
+
_ipt = _ipd.get("tasks", _ipd) if isinstance(_ipd, dict) else _ipd
|
|
515
|
+
if isinstance(_ipt, list) and _ipt:
|
|
516
|
+
_f = _ipt[0]
|
|
517
|
+
if isinstance(_f, dict):
|
|
518
|
+
_sk_current_task = (
|
|
519
|
+
_f.get("title", "")
|
|
520
|
+
or _f.get("payload", {}).get("action", "")
|
|
521
|
+
or _f.get("id", "")
|
|
522
|
+
)
|
|
523
|
+
except (json.JSONDecodeError, KeyError, AttributeError):
|
|
524
|
+
pass
|
|
525
|
+
|
|
526
|
+
if not _sk_current_task:
|
|
527
|
+
_ctf = loki_dir / "queue" / "current-task.json"
|
|
528
|
+
if _ctf.exists():
|
|
529
|
+
try:
|
|
530
|
+
_ct = _safe_json_read(_ctf, {})
|
|
531
|
+
if isinstance(_ct, dict):
|
|
532
|
+
_sk_current_task = (
|
|
533
|
+
_ct.get("title", "")
|
|
534
|
+
or _ct.get("payload", {}).get("action", "")
|
|
535
|
+
or _ct.get("id", "")
|
|
536
|
+
)
|
|
537
|
+
except (json.JSONDecodeError, KeyError, AttributeError):
|
|
538
|
+
pass
|
|
539
|
+
|
|
540
|
+
# Build a change hash to avoid redundant broadcasts
|
|
541
|
+
_sk_hash = f"{_sk_phase}:{_sk_iteration}:{_sk_pending}:{_sk_current_task}"
|
|
542
|
+
if _sk_hash != _last_skill_hash:
|
|
543
|
+
_last_skill_hash = _sk_hash
|
|
544
|
+
payload = {
|
|
545
|
+
"status": "running",
|
|
546
|
+
"phase": _sk_phase,
|
|
547
|
+
"iteration": _sk_iteration,
|
|
548
|
+
"complexity": _sk_complexity,
|
|
549
|
+
"mode": "autonomous",
|
|
550
|
+
"provider": _sd.get("provider", "claude"),
|
|
551
|
+
"running_agents": 0,
|
|
552
|
+
"pending_tasks": _sk_pending,
|
|
553
|
+
"current_task": _sk_current_task,
|
|
554
|
+
"version": _sk_version,
|
|
555
|
+
}
|
|
556
|
+
await manager.broadcast({
|
|
557
|
+
"type": "status_update",
|
|
558
|
+
"data": payload,
|
|
559
|
+
})
|
|
560
|
+
_broadcast_sent = True
|
|
561
|
+
except (json.JSONDecodeError, OSError, KeyError):
|
|
562
|
+
pass
|
|
563
|
+
|
|
429
564
|
# Poll faster when a session is running
|
|
430
565
|
pid_file = loki_dir / "loki.pid"
|
|
431
566
|
is_running = False
|
|
@@ -437,6 +572,15 @@ async def _push_loki_state_loop() -> None:
|
|
|
437
572
|
except (ValueError, OSError, ProcessLookupError):
|
|
438
573
|
pass
|
|
439
574
|
|
|
575
|
+
# Also consider skill sessions as "running" for poll interval
|
|
576
|
+
if not is_running and _session_file.exists():
|
|
577
|
+
try:
|
|
578
|
+
_sd2 = _safe_json_read(_session_file, {})
|
|
579
|
+
if _sd2.get("status") == "running":
|
|
580
|
+
is_running = True
|
|
581
|
+
except (json.JSONDecodeError, KeyError):
|
|
582
|
+
pass
|
|
583
|
+
|
|
440
584
|
await asyncio.sleep(2.0 if is_running else 30.0)
|
|
441
585
|
except asyncio.CancelledError:
|
|
442
586
|
return
|
|
@@ -598,9 +742,12 @@ async def get_status() -> StatusResponse:
|
|
|
598
742
|
running_agents = 0
|
|
599
743
|
|
|
600
744
|
# Read dashboard state (with retry for concurrent writes)
|
|
745
|
+
_has_dashboard_state = False
|
|
601
746
|
if state_file.exists():
|
|
602
747
|
try:
|
|
603
748
|
state = _safe_json_read(state_file, {})
|
|
749
|
+
if state:
|
|
750
|
+
_has_dashboard_state = True
|
|
604
751
|
phase = state.get("phase", "")
|
|
605
752
|
iteration = state.get("iteration", 0)
|
|
606
753
|
complexity = state.get("complexity", "standard")
|
|
@@ -641,14 +788,113 @@ async def get_status() -> StatusResponse:
|
|
|
641
788
|
pass
|
|
642
789
|
|
|
643
790
|
# Also check session.json for skill-invoked sessions
|
|
791
|
+
_skill_session = False
|
|
644
792
|
if not running and session_file.exists():
|
|
645
793
|
try:
|
|
646
794
|
sd = _safe_json_read(session_file, {})
|
|
647
795
|
if sd.get("status") == "running":
|
|
648
|
-
|
|
796
|
+
# Validate freshness: session.json must have been updated within
|
|
797
|
+
# the last 5 minutes to be considered active (skill agents update
|
|
798
|
+
# it each turn). Fall back to file mtime if no timestamp field.
|
|
799
|
+
_session_fresh = True
|
|
800
|
+
_session_ts = sd.get("updatedAt") or sd.get("startedAt", "")
|
|
801
|
+
if _session_ts:
|
|
802
|
+
try:
|
|
803
|
+
_sdt = datetime.fromisoformat(
|
|
804
|
+
_session_ts.replace("Z", "+00:00")
|
|
805
|
+
)
|
|
806
|
+
if _sdt.tzinfo is None:
|
|
807
|
+
_sdt = _sdt.replace(tzinfo=timezone.utc)
|
|
808
|
+
_age = (datetime.now(timezone.utc) - _sdt).total_seconds()
|
|
809
|
+
if _age > 300:
|
|
810
|
+
_session_fresh = False
|
|
811
|
+
except (ValueError, AttributeError):
|
|
812
|
+
pass
|
|
813
|
+
else:
|
|
814
|
+
# No timestamp -- check file mtime
|
|
815
|
+
try:
|
|
816
|
+
_mtime = session_file.stat().st_mtime
|
|
817
|
+
_age = time.time() - _mtime
|
|
818
|
+
if _age > 300:
|
|
819
|
+
_session_fresh = False
|
|
820
|
+
except OSError:
|
|
821
|
+
pass
|
|
822
|
+
|
|
823
|
+
if _session_fresh:
|
|
824
|
+
running = True
|
|
825
|
+
_skill_session = True
|
|
826
|
+
# Pull provider from session.json if available
|
|
827
|
+
_sp = sd.get("provider", "")
|
|
828
|
+
if _sp:
|
|
829
|
+
provider = _sp
|
|
649
830
|
except (json.JSONDecodeError, KeyError):
|
|
650
831
|
pass
|
|
651
832
|
|
|
833
|
+
# When running as a skill (no dashboard-state.json), read state from
|
|
834
|
+
# the orchestrator and queue files that the skill agent writes directly.
|
|
835
|
+
if _skill_session and not _has_dashboard_state:
|
|
836
|
+
orch_file = loki_dir / "state" / "orchestrator.json"
|
|
837
|
+
if orch_file.exists():
|
|
838
|
+
try:
|
|
839
|
+
orch = _safe_json_read(orch_file, {})
|
|
840
|
+
phase = orch.get("currentPhase", phase) or phase
|
|
841
|
+
iteration = orch.get("iteration", iteration)
|
|
842
|
+
complexity = orch.get("complexity", complexity) or complexity
|
|
843
|
+
_metrics = orch.get("metrics", {})
|
|
844
|
+
if isinstance(_metrics, dict):
|
|
845
|
+
_tc = _metrics.get("tasksCompleted", 0)
|
|
846
|
+
_tf = _metrics.get("tasksFailed", 0)
|
|
847
|
+
if isinstance(_tc, (int, float)):
|
|
848
|
+
pass # available for future use
|
|
849
|
+
except (json.JSONDecodeError, KeyError):
|
|
850
|
+
pass
|
|
851
|
+
|
|
852
|
+
# Read pending task count from queue files
|
|
853
|
+
_q_pending = loki_dir / "queue" / "pending.json"
|
|
854
|
+
if _q_pending.exists():
|
|
855
|
+
try:
|
|
856
|
+
_qd = _safe_json_read(_q_pending, [])
|
|
857
|
+
_tasks = _qd.get("tasks", _qd) if isinstance(_qd, dict) else _qd
|
|
858
|
+
if isinstance(_tasks, list):
|
|
859
|
+
pending_tasks = len(_tasks)
|
|
860
|
+
except (json.JSONDecodeError, KeyError, AttributeError):
|
|
861
|
+
pass
|
|
862
|
+
|
|
863
|
+
# Read current task from in-progress queue
|
|
864
|
+
_q_inprog = loki_dir / "queue" / "in-progress.json"
|
|
865
|
+
if _q_inprog.exists():
|
|
866
|
+
try:
|
|
867
|
+
_ipd = _safe_json_read(_q_inprog, [])
|
|
868
|
+
_ip_tasks = _ipd.get("tasks", _ipd) if isinstance(_ipd, dict) else _ipd
|
|
869
|
+
if isinstance(_ip_tasks, list) and _ip_tasks:
|
|
870
|
+
_first = _ip_tasks[0]
|
|
871
|
+
if isinstance(_first, dict):
|
|
872
|
+
current_task = (
|
|
873
|
+
_first.get("title", "")
|
|
874
|
+
or _first.get("payload", {}).get("action", "")
|
|
875
|
+
or _first.get("id", "")
|
|
876
|
+
)
|
|
877
|
+
except (json.JSONDecodeError, KeyError, AttributeError):
|
|
878
|
+
pass
|
|
879
|
+
|
|
880
|
+
# Read current-task.json (skill agents write this when claiming a task)
|
|
881
|
+
_q_current = loki_dir / "queue" / "current-task.json"
|
|
882
|
+
if not current_task and _q_current.exists():
|
|
883
|
+
try:
|
|
884
|
+
_ct = _safe_json_read(_q_current, {})
|
|
885
|
+
if isinstance(_ct, dict):
|
|
886
|
+
current_task = (
|
|
887
|
+
_ct.get("title", "")
|
|
888
|
+
or _ct.get("payload", {}).get("action", "")
|
|
889
|
+
or _ct.get("id", "")
|
|
890
|
+
)
|
|
891
|
+
except (json.JSONDecodeError, KeyError, AttributeError):
|
|
892
|
+
pass
|
|
893
|
+
|
|
894
|
+
# Skill sessions are autonomous by definition
|
|
895
|
+
if not mode:
|
|
896
|
+
mode = "autonomous"
|
|
897
|
+
|
|
652
898
|
# Determine status string
|
|
653
899
|
if not running:
|
|
654
900
|
status = "stopped"
|
package/docs/INSTALLATION.md
CHANGED
package/mcp/__init__.py
CHANGED