loki-mode 7.9.0 → 7.10.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/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/lib/efficiency_cost.py +170 -0
- package/autonomy/lib/proof-generator.py +37 -47
- package/autonomy/loki +46 -0
- package/dashboard/__init__.py +1 -1
- package/docs/INSTALLATION.md +1 -1
- package/loki-ts/dist/loki.js +2 -2
- 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: Autonomous spec-to-product system. Triggers on "Loki Mode". Takes a spec (PRD, GitHub issue, OpenAPI doc, etc.) to deployed product via the RARV-C closure loop, with minimal human intervention. Provider-agnostic. Requires --dangerously-skip-permissions flag.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Loki Mode v7.
|
|
6
|
+
# Loki Mode v7.10.0
|
|
7
7
|
|
|
8
8
|
**You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
|
|
9
9
|
|
|
@@ -381,4 +381,4 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
|
|
|
381
381
|
|
|
382
382
|
---
|
|
383
383
|
|
|
384
|
-
**v7.
|
|
384
|
+
**v7.10.0 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
7.
|
|
1
|
+
7.10.0
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Shared efficiency + cost collection for Loki Mode.
|
|
3
|
+
|
|
4
|
+
This module is the single source of truth for reading per-iteration
|
|
5
|
+
efficiency records out of .loki/metrics/efficiency/ and turning them into a
|
|
6
|
+
cost dict. It was extracted from autonomy/lib/proof-generator.py (R1) so that
|
|
7
|
+
both the proof generator and the R2 benchmark adapters compute cost the same
|
|
8
|
+
way ("bench cost == proof cost"). proof-generator.py has a hyphen in its name
|
|
9
|
+
and is therefore not importable as a module, which is why the logic lives
|
|
10
|
+
here instead.
|
|
11
|
+
|
|
12
|
+
Behavior contract (preserved from the R1 proof generator):
|
|
13
|
+
- cost.usd is None when NO valid efficiency record was read (cost was never
|
|
14
|
+
collected for this run). A skeptic seeing "$0.00" assumes the artifact is
|
|
15
|
+
fake; "cost not recorded" is the honest signal.
|
|
16
|
+
- A genuine 0.0 (records existed but summed to zero) is preserved as 0.0.
|
|
17
|
+
- usd is rounded to 4 decimals only when records were collected.
|
|
18
|
+
|
|
19
|
+
The token->USD pricing helper (price_from_tokens) lives here too so that
|
|
20
|
+
adapters and the report compute uniform cost from a single dated price table
|
|
21
|
+
(benchmarks/bench/prices.json) when a tool reports tokens but no native
|
|
22
|
+
cost_usd. This is additive: the proof generator does not use it.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
import json
|
|
26
|
+
import os
|
|
27
|
+
|
|
28
|
+
__all__ = [
|
|
29
|
+
"collect_efficiency",
|
|
30
|
+
"load_prices",
|
|
31
|
+
"price_from_tokens",
|
|
32
|
+
"DEFAULT_PRICES_PATH",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
# benchmarks/bench/prices.json relative to the repo root. Resolved lazily so
|
|
36
|
+
# importing this module never depends on cwd or on the file existing.
|
|
37
|
+
_HERE = os.path.dirname(os.path.abspath(__file__))
|
|
38
|
+
_REPO_ROOT = os.path.dirname(os.path.dirname(_HERE)) # autonomy/lib -> repo
|
|
39
|
+
DEFAULT_PRICES_PATH = os.path.join(
|
|
40
|
+
_REPO_ROOT, "benchmarks", "bench", "prices.json"
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
# ---------------------------------------------------------------------------
|
|
45
|
+
# small helpers (self-contained copies; proof-generator.py keeps its own)
|
|
46
|
+
# ---------------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
def _read_json(path, default=None):
|
|
49
|
+
try:
|
|
50
|
+
with open(path, "r") as f:
|
|
51
|
+
return json.load(f)
|
|
52
|
+
except Exception:
|
|
53
|
+
return default
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def _to_int(v, default=0):
|
|
57
|
+
try:
|
|
58
|
+
return int(v)
|
|
59
|
+
except Exception:
|
|
60
|
+
return default
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _to_float(v, default=0.0):
|
|
64
|
+
try:
|
|
65
|
+
return float(v)
|
|
66
|
+
except Exception:
|
|
67
|
+
return default
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
# ---------------------------------------------------------------------------
|
|
71
|
+
# efficiency collection (extracted verbatim from proof-generator.py)
|
|
72
|
+
# ---------------------------------------------------------------------------
|
|
73
|
+
|
|
74
|
+
def collect_efficiency(loki_dir):
|
|
75
|
+
"""Sum cost + tokens across .loki/metrics/efficiency/iteration-*.json.
|
|
76
|
+
|
|
77
|
+
Returns (cost dict, best-effort model name (last non-empty seen)).
|
|
78
|
+
|
|
79
|
+
Credibility: cost.usd is set to None when NO valid efficiency record was
|
|
80
|
+
read (cost was never collected for this run). A skeptic seeing "$0.00" on
|
|
81
|
+
HN assumes the artifact is fake; "cost not recorded" is the honest signal.
|
|
82
|
+
A genuine 0.0 (records existed but summed to zero) is preserved as 0.0.
|
|
83
|
+
"""
|
|
84
|
+
cost = {
|
|
85
|
+
"usd": 0.0,
|
|
86
|
+
"input_tokens": 0,
|
|
87
|
+
"output_tokens": 0,
|
|
88
|
+
"cache_read_tokens": 0,
|
|
89
|
+
"cache_creation_tokens": 0,
|
|
90
|
+
}
|
|
91
|
+
model = ""
|
|
92
|
+
collected = False
|
|
93
|
+
eff_dir = os.path.join(loki_dir, "metrics", "efficiency")
|
|
94
|
+
try:
|
|
95
|
+
names = sorted(os.listdir(eff_dir))
|
|
96
|
+
except Exception:
|
|
97
|
+
names = []
|
|
98
|
+
for name in names:
|
|
99
|
+
if not (name.startswith("iteration-") and name.endswith(".json")):
|
|
100
|
+
continue
|
|
101
|
+
rec = _read_json(os.path.join(eff_dir, name), default=None)
|
|
102
|
+
if not isinstance(rec, dict):
|
|
103
|
+
continue
|
|
104
|
+
collected = True
|
|
105
|
+
cost["usd"] += _to_float(rec.get("cost_usd"))
|
|
106
|
+
cost["input_tokens"] += _to_int(rec.get("input_tokens"))
|
|
107
|
+
cost["output_tokens"] += _to_int(rec.get("output_tokens"))
|
|
108
|
+
cost["cache_read_tokens"] += _to_int(rec.get("cache_read_tokens"))
|
|
109
|
+
cost["cache_creation_tokens"] += _to_int(rec.get("cache_creation_tokens"))
|
|
110
|
+
if rec.get("model"):
|
|
111
|
+
model = str(rec.get("model"))
|
|
112
|
+
if collected:
|
|
113
|
+
# Round usd to a sane precision but keep it precise (anti-pattern:
|
|
114
|
+
# round suspiciously-clean numbers). 4 decimals preserves odd values.
|
|
115
|
+
cost["usd"] = round(cost["usd"], 4)
|
|
116
|
+
else:
|
|
117
|
+
# No efficiency files were read: cost was not collected for this run.
|
|
118
|
+
cost["usd"] = None
|
|
119
|
+
return cost, model
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
# ---------------------------------------------------------------------------
|
|
123
|
+
# uniform token -> USD pricing (R2 benchmark; not used by the proof generator)
|
|
124
|
+
# ---------------------------------------------------------------------------
|
|
125
|
+
|
|
126
|
+
def load_prices(path=None):
|
|
127
|
+
"""Load the shared dated price table. Returns {} if missing/unreadable.
|
|
128
|
+
|
|
129
|
+
Never raises: a missing price table means we cannot price tokens, which is
|
|
130
|
+
an honest null, not a fabricated zero.
|
|
131
|
+
"""
|
|
132
|
+
p = path or DEFAULT_PRICES_PATH
|
|
133
|
+
data = _read_json(p, default=None)
|
|
134
|
+
if not isinstance(data, dict):
|
|
135
|
+
return {}
|
|
136
|
+
return data
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def price_from_tokens(model, input_tokens, output_tokens,
|
|
140
|
+
cache_read_tokens=0, prices=None, prices_path=None):
|
|
141
|
+
"""Compute a USD cost from raw token counts and the shared price table.
|
|
142
|
+
|
|
143
|
+
Returns a float (rounded to 6 decimals) when the model is present in the
|
|
144
|
+
price table, else None. None means "cannot price" (honest), never 0.0.
|
|
145
|
+
|
|
146
|
+
Pricing is per million tokens (mtok). cache_read is priced separately from
|
|
147
|
+
fresh input tokens. Used for tools that expose token counts but not a
|
|
148
|
+
native cost_usd; keeps cross-tool cost comparison on one pricing basis.
|
|
149
|
+
"""
|
|
150
|
+
table = prices if prices is not None else load_prices(prices_path)
|
|
151
|
+
models = table.get("models") if isinstance(table, dict) else None
|
|
152
|
+
if not isinstance(models, dict):
|
|
153
|
+
return None
|
|
154
|
+
entry = models.get(model)
|
|
155
|
+
if not isinstance(entry, dict):
|
|
156
|
+
return None
|
|
157
|
+
in_rate = _to_float(entry.get("input_per_mtok"), None)
|
|
158
|
+
out_rate = _to_float(entry.get("output_per_mtok"), None)
|
|
159
|
+
cache_rate = _to_float(entry.get("cache_read_per_mtok"), 0.0)
|
|
160
|
+
if in_rate is None or out_rate is None:
|
|
161
|
+
return None
|
|
162
|
+
it = _to_int(input_tokens)
|
|
163
|
+
ot = _to_int(output_tokens)
|
|
164
|
+
ct = _to_int(cache_read_tokens)
|
|
165
|
+
usd = (
|
|
166
|
+
(it / 1_000_000.0) * in_rate
|
|
167
|
+
+ (ot / 1_000_000.0) * out_rate
|
|
168
|
+
+ (ct / 1_000_000.0) * cache_rate
|
|
169
|
+
)
|
|
170
|
+
return round(usd, 6)
|
|
@@ -35,6 +35,7 @@ if _HERE not in sys.path:
|
|
|
35
35
|
sys.path.insert(0, _HERE)
|
|
36
36
|
|
|
37
37
|
import proof_redact # noqa: E402
|
|
38
|
+
from efficiency_cost import collect_efficiency as _collect_efficiency # noqa: E402
|
|
38
39
|
|
|
39
40
|
|
|
40
41
|
# ---------------------------------------------------------------------------
|
|
@@ -85,52 +86,10 @@ def _to_float(v, default=0.0):
|
|
|
85
86
|
# data collection
|
|
86
87
|
# ---------------------------------------------------------------------------
|
|
87
88
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
Credibility: cost.usd is set to None when NO valid efficiency record was
|
|
94
|
-
read (cost was never collected for this run). A skeptic seeing "$0.00" on
|
|
95
|
-
HN assumes the artifact is fake; "cost not recorded" is the honest signal.
|
|
96
|
-
A genuine 0.0 (records existed but summed to zero) is preserved as 0.0.
|
|
97
|
-
"""
|
|
98
|
-
cost = {
|
|
99
|
-
"usd": 0.0,
|
|
100
|
-
"input_tokens": 0,
|
|
101
|
-
"output_tokens": 0,
|
|
102
|
-
"cache_read_tokens": 0,
|
|
103
|
-
"cache_creation_tokens": 0,
|
|
104
|
-
}
|
|
105
|
-
model = ""
|
|
106
|
-
collected = False
|
|
107
|
-
eff_dir = os.path.join(loki_dir, "metrics", "efficiency")
|
|
108
|
-
try:
|
|
109
|
-
names = sorted(os.listdir(eff_dir))
|
|
110
|
-
except Exception:
|
|
111
|
-
names = []
|
|
112
|
-
for name in names:
|
|
113
|
-
if not (name.startswith("iteration-") and name.endswith(".json")):
|
|
114
|
-
continue
|
|
115
|
-
rec = _read_json(os.path.join(eff_dir, name), default=None)
|
|
116
|
-
if not isinstance(rec, dict):
|
|
117
|
-
continue
|
|
118
|
-
collected = True
|
|
119
|
-
cost["usd"] += _to_float(rec.get("cost_usd"))
|
|
120
|
-
cost["input_tokens"] += _to_int(rec.get("input_tokens"))
|
|
121
|
-
cost["output_tokens"] += _to_int(rec.get("output_tokens"))
|
|
122
|
-
cost["cache_read_tokens"] += _to_int(rec.get("cache_read_tokens"))
|
|
123
|
-
cost["cache_creation_tokens"] += _to_int(rec.get("cache_creation_tokens"))
|
|
124
|
-
if rec.get("model"):
|
|
125
|
-
model = str(rec.get("model"))
|
|
126
|
-
if collected:
|
|
127
|
-
# Round usd to a sane precision but keep it precise (anti-pattern:
|
|
128
|
-
# round suspiciously-clean numbers). 4 decimals preserves odd values.
|
|
129
|
-
cost["usd"] = round(cost["usd"], 4)
|
|
130
|
-
else:
|
|
131
|
-
# No efficiency files were read: cost was not collected for this run.
|
|
132
|
-
cost["usd"] = None
|
|
133
|
-
return cost, model
|
|
89
|
+
# _collect_efficiency was extracted to autonomy/lib/efficiency_cost.py (R2) so
|
|
90
|
+
# the benchmark adapters and this generator compute cost identically. It is
|
|
91
|
+
# imported at the top of this file as _collect_efficiency; the behavior
|
|
92
|
+
# (None usd when uncollected, 0.0 preserved, 4-decimal rounding) is unchanged.
|
|
134
93
|
|
|
135
94
|
|
|
136
95
|
def _collect_council(loki_dir):
|
|
@@ -143,7 +102,15 @@ def _collect_council(loki_dir):
|
|
|
143
102
|
if isinstance(verdicts, list) and verdicts:
|
|
144
103
|
last = verdicts[-1]
|
|
145
104
|
if isinstance(last, dict):
|
|
146
|
-
|
|
105
|
+
# completion-council.sh writes verdicts[] entries as
|
|
106
|
+
# {iteration, timestamp, approve, reject, result} where "result" is
|
|
107
|
+
# APPROVED / REJECTED. Older/alt shapes may use verdict/decision.
|
|
108
|
+
final_verdict = str(
|
|
109
|
+
last.get("result")
|
|
110
|
+
or last.get("verdict")
|
|
111
|
+
or last.get("decision")
|
|
112
|
+
or ""
|
|
113
|
+
)
|
|
147
114
|
else:
|
|
148
115
|
final_verdict = str(last)
|
|
149
116
|
threshold = state.get("threshold")
|
|
@@ -171,6 +138,29 @@ def _collect_council(loki_dir):
|
|
|
171
138
|
"summary": str(rec.get("summary") or rec.get("rationale") or ""),
|
|
172
139
|
})
|
|
173
140
|
|
|
141
|
+
# Fallback: completion-council.sh records the aggregate tally in state.json
|
|
142
|
+
# (approve_votes / reject_votes) and the per-iteration detail under
|
|
143
|
+
# council/votes/iteration-N/, which may not be present as flat *.json here.
|
|
144
|
+
# If we found no per-reviewer files but the council ran, synthesize a single
|
|
145
|
+
# tally row from the aggregate so the proof's council section is populated
|
|
146
|
+
# rather than blank (the council outcome is the central trust signal).
|
|
147
|
+
approve_votes = state.get("approve_votes")
|
|
148
|
+
reject_votes = state.get("reject_votes")
|
|
149
|
+
if not reviewers and (enabled or verdicts or approve_votes or reject_votes):
|
|
150
|
+
a = int(approve_votes or 0)
|
|
151
|
+
r = int(reject_votes or 0)
|
|
152
|
+
if a or r or final_verdict:
|
|
153
|
+
reviewers.append({
|
|
154
|
+
"role": "council (aggregate)",
|
|
155
|
+
"vote": final_verdict or ("APPROVED" if a > r else "REJECTED"),
|
|
156
|
+
"summary": "%d approve / %d reject across council voting" % (a, r),
|
|
157
|
+
})
|
|
158
|
+
# Derive a human threshold ratio when not explicitly recorded.
|
|
159
|
+
if threshold is None and (a or r):
|
|
160
|
+
total = a + r
|
|
161
|
+
if total:
|
|
162
|
+
threshold = "%d/%d" % (a, total)
|
|
163
|
+
|
|
174
164
|
return {
|
|
175
165
|
"enabled": enabled,
|
|
176
166
|
"final_verdict": final_verdict,
|
package/autonomy/loki
CHANGED
|
@@ -567,6 +567,7 @@ show_help() {
|
|
|
567
567
|
echo " report [opts] Session report generator (--format text|markdown|html, --output)"
|
|
568
568
|
echo " share [opts] Share session report as GitHub Gist (--private, --format)"
|
|
569
569
|
echo " proof [cmd] Inspect/share proof-of-run artifacts (list|show|open|share)"
|
|
570
|
+
echo " bench [cmd] Head-to-head benchmark harness (run|vs|list|verify|report)"
|
|
570
571
|
echo " version Show version"
|
|
571
572
|
echo " help Show this help"
|
|
572
573
|
echo ""
|
|
@@ -13078,6 +13079,9 @@ main() {
|
|
|
13078
13079
|
proof)
|
|
13079
13080
|
cmd_proof "$@"
|
|
13080
13081
|
;;
|
|
13082
|
+
bench)
|
|
13083
|
+
cmd_bench "$@"
|
|
13084
|
+
;;
|
|
13081
13085
|
context|ctx)
|
|
13082
13086
|
cmd_context "$@"
|
|
13083
13087
|
;;
|
|
@@ -24541,6 +24545,48 @@ _loki_gist_upload() {
|
|
|
24541
24545
|
echo -e "${GREEN}Shared: ${gist_url}${NC}"
|
|
24542
24546
|
}
|
|
24543
24547
|
|
|
24548
|
+
# loki bench - head-to-head benchmark harness (R2).
|
|
24549
|
+
# Subcommands: run <task> | vs <task> | list | verify <result.json>.
|
|
24550
|
+
# Thin pass-through to benchmarks/bench/run.sh (shared python core runner.py).
|
|
24551
|
+
# CREDIBILITY: Loki NEVER grades its own success. Success is decided by a
|
|
24552
|
+
# held-out acceptance command run by the grader OUTSIDE the agent (exit code).
|
|
24553
|
+
# No council / RARV-C / LLM-judge participates in scoring. See
|
|
24554
|
+
# benchmarks/SCHEMA-adapter.md and benchmarks/SCHEMA-result.md.
|
|
24555
|
+
cmd_bench() {
|
|
24556
|
+
local bench_sh="$SKILL_DIR/benchmarks/bench/run.sh"
|
|
24557
|
+
if [ ! -f "$bench_sh" ]; then
|
|
24558
|
+
log_error "benchmark harness not found: $bench_sh"
|
|
24559
|
+
return 1
|
|
24560
|
+
fi
|
|
24561
|
+
local sub="${1:-}"
|
|
24562
|
+
case "$sub" in
|
|
24563
|
+
""|--help|-h|help)
|
|
24564
|
+
echo -e "${BOLD}loki bench${NC} - head-to-head benchmark harness (R2)"
|
|
24565
|
+
echo ""
|
|
24566
|
+
echo "Usage: loki bench <subcommand> [args] [options]"
|
|
24567
|
+
echo ""
|
|
24568
|
+
echo "Subcommands:"
|
|
24569
|
+
echo " run <task> Run Loki only on a task-spec"
|
|
24570
|
+
echo " vs <task> Run all configured tools on a task-spec (head-to-head)"
|
|
24571
|
+
echo " list List available task-specs"
|
|
24572
|
+
echo " verify <file> Recompute task_hash + check tool versions for a result.json"
|
|
24573
|
+
echo " report <files> Build results.json + RESULTS.md from per-tool result-rows"
|
|
24574
|
+
echo ""
|
|
24575
|
+
echo "Options:"
|
|
24576
|
+
echo " --trials N Number of trials per tool (default 3)"
|
|
24577
|
+
echo " --model NAME Override the model"
|
|
24578
|
+
echo " --emit-proof Emit an R1 proof-of-run for the Loki trial(s)"
|
|
24579
|
+
echo " --out-dir DIR (report) output dir for results.json + RESULTS.md"
|
|
24580
|
+
echo ""
|
|
24581
|
+
echo "Loki NEVER grades its own success: a held-out acceptance command run"
|
|
24582
|
+
echo "by the grader OUTSIDE the agent decides success by exit code."
|
|
24583
|
+
[ "$sub" = "" ] && return 1
|
|
24584
|
+
return 0
|
|
24585
|
+
;;
|
|
24586
|
+
esac
|
|
24587
|
+
bash "$bench_sh" "$@"
|
|
24588
|
+
}
|
|
24589
|
+
|
|
24544
24590
|
# loki proof - inspect and share proof-of-run artifacts (.loki/proofs/<id>/).
|
|
24545
24591
|
# Subcommands: list | show <id> | open <id> | share <id>.
|
|
24546
24592
|
# The proof.json schema is frozen (R1 spec). Reads are tolerant of missing
|
package/dashboard/__init__.py
CHANGED
package/docs/INSTALLATION.md
CHANGED
package/loki-ts/dist/loki.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var N7=Object.defineProperty;var k7=(K)=>K;function D7(K,$){this[K]=k7.bind(null,$)}var v=(K,$)=>{for(var Q in $)N7(K,Q,{get:$[Q],enumerable:!0,configurable:!0,set:D7.bind($,Q)})};var E=(K,$)=>()=>(K&&($=K(K=0)),$);var $1=import.meta.require;var z0={};v(z0,{lokiDir:()=>R,homeLokiDir:()=>v1,findRepoRootForVersion:()=>y1,REPO_ROOT:()=>c});import{resolve as p,dirname as b1}from"path";import{fileURLToPath as C7}from"url";import{existsSync as O1}from"fs";import{homedir as h7}from"os";function b7(){let K=Z0;for(let $=0;$<6;$++){if(O1(p(K,"VERSION"))&&O1(p(K,"autonomy/run.sh")))return K;let Q=b1(K);if(Q===K)break;K=Q}return p(Z0,"..","..","..")}function y1(K){let $=K;for(let Q=0;Q<6;Q++){if(O1(p($,"VERSION"))&&O1(p($,"autonomy/run.sh")))return $;let X=b1($);if(X===$)break;$=X}return p(K,"..","..","..")}function R(){return process.env.LOKI_DIR??p(process.cwd(),".loki")}function v1(){return p(h7(),".loki")}var Z0,c;var g=E(()=>{Z0=b1(C7(import.meta.url));c=b7()});import{readFileSync as y7}from"fs";import{resolve as v7,dirname as g7}from"path";import{fileURLToPath as m7}from"url";function T1(){if(r!==null)return r;let K="7.
|
|
2
|
+
var N7=Object.defineProperty;var k7=(K)=>K;function D7(K,$){this[K]=k7.bind(null,$)}var v=(K,$)=>{for(var Q in $)N7(K,Q,{get:$[Q],enumerable:!0,configurable:!0,set:D7.bind($,Q)})};var E=(K,$)=>()=>(K&&($=K(K=0)),$);var $1=import.meta.require;var z0={};v(z0,{lokiDir:()=>R,homeLokiDir:()=>v1,findRepoRootForVersion:()=>y1,REPO_ROOT:()=>c});import{resolve as p,dirname as b1}from"path";import{fileURLToPath as C7}from"url";import{existsSync as O1}from"fs";import{homedir as h7}from"os";function b7(){let K=Z0;for(let $=0;$<6;$++){if(O1(p(K,"VERSION"))&&O1(p(K,"autonomy/run.sh")))return K;let Q=b1(K);if(Q===K)break;K=Q}return p(Z0,"..","..","..")}function y1(K){let $=K;for(let Q=0;Q<6;Q++){if(O1(p($,"VERSION"))&&O1(p($,"autonomy/run.sh")))return $;let X=b1($);if(X===$)break;$=X}return p(K,"..","..","..")}function R(){return process.env.LOKI_DIR??p(process.cwd(),".loki")}function v1(){return p(h7(),".loki")}var Z0,c;var g=E(()=>{Z0=b1(C7(import.meta.url));c=b7()});import{readFileSync as y7}from"fs";import{resolve as v7,dirname as g7}from"path";import{fileURLToPath as m7}from"url";function T1(){if(r!==null)return r;let K="7.10.0";if(typeof K==="string"&&K.length>0)return r=K,r;try{let $=g7(m7(import.meta.url)),Q=y1($);r=y7(v7(Q,"VERSION"),"utf-8").trim()}catch{r="unknown"}return r}var r=null;var g1=E(()=>{g()});var U0={};v(U0,{runOrThrow:()=>f7,run:()=>N,commandVersion:()=>p7,commandExists:()=>y,ShellError:()=>m1});async function N(K,$={}){let Q=Bun.spawn({cmd:[...K],stdout:"pipe",stderr:"pipe",env:$.env?{...process.env,...$.env}:process.env,cwd:$.cwd}),X,Z;if($.timeoutMs&&$.timeoutMs>0)X=setTimeout(()=>{try{Q.kill("SIGTERM")}catch{}Z=setTimeout(()=>{try{Q.kill("SIGKILL")}catch{}},2000)},$.timeoutMs);try{let[z,H,V]=await Promise.all([new Response(Q.stdout).text(),new Response(Q.stderr).text(),Q.exited]);return{stdout:z,stderr:H,exitCode:V}}finally{if(X)clearTimeout(X);if(Z)clearTimeout(Z)}}async function f7(K,$={}){let Q=await N(K,$);if(Q.exitCode!==0)throw new m1(`command failed (${Q.exitCode}): ${K.join(" ")}`,Q.exitCode,Q.stdout,Q.stderr);return Q}async function y(K){let $=u7(K),Q=await N(["sh","-c",`command -v ${$}`],{timeoutMs:5000});if(Q.exitCode===0)return Q.stdout.trim()||null;return null}function u7(K){if(!/^[A-Za-z0-9._/-]+$/.test(K))throw Error(`refused to shell-escape suspect token: ${K}`);return K}async function p7(K,$="--version"){if(!await y(K))return null;let X=await N([K,$],{timeoutMs:5000});if(X.exitCode!==0)return null;return((X.stdout||X.stderr).split(/\r?\n/)[0]?.trim()??"")||null}var m1;var l=E(()=>{m1=class m1 extends Error{message;exitCode;stdout;stderr;constructor(K,$,Q,X){super(K);this.message=K;this.exitCode=$;this.stdout=Q;this.stderr=X;this.name="ShellError"}}});function d(K){return c7?"":K}var c7,A,h,w,u6,_,k,D,U;var o=E(()=>{c7=(process.env.NO_COLOR??"").length>0;A=d("\x1B[0;31m"),h=d("\x1B[0;32m"),w=d("\x1B[1;33m"),u6=d("\x1B[0;34m"),_=d("\x1B[0;36m"),k=d("\x1B[1m"),D=d("\x1B[2m"),U=d("\x1B[0m")});import{existsSync as e7}from"fs";async function Q1(){if(V1!==void 0)return V1;let K="/opt/homebrew/bin/python3.12";if(e7(K))return V1=K,K;let $=await y("python3.12");if($)return V1=$,$;let Q=await y("python3");return V1=Q,Q}async function t(K,$={}){let Q=await Q1();if(!Q)return{stdout:"",stderr:"python3 not found",exitCode:127};return N([Q,"-c",K],$)}var V1;var W1=E(()=>{l()});var A0={};v(A0,{runStatus:()=>B5});import{existsSync as C,readFileSync as Z1,readdirSync as G0,statSync as B0}from"fs";import{resolve as S,basename as Z5}from"path";import{homedir as z5}from"os";async function U5(){if(await y("jq"))return!0;return process.stdout.write(`${A}Error: jq is required but not installed.${U}
|
|
3
3
|
`),process.stdout.write(`Install with:
|
|
4
4
|
`),process.stdout.write(` brew install jq (macOS)
|
|
5
5
|
`),process.stdout.write(` apt install jq (Debian/Ubuntu)
|
|
@@ -667,4 +667,4 @@ Set LOKI_LEGACY_BASH=1 to force the bash CLI for every command.
|
|
|
667
667
|
`),2}default:return process.stderr.write(`Unknown command: ${$}
|
|
668
668
|
`),process.stderr.write(S7),2}}process.on("SIGINT",()=>process.exit(130));process.on("SIGTERM",()=>process.exit(143));var x6=await w6(Bun.argv.slice(2));process.exit(x6);
|
|
669
669
|
|
|
670
|
-
//# debugId=
|
|
670
|
+
//# debugId=2ABFCEF23EFA3C0364756E2164756E21
|
package/mcp/__init__.py
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "loki-mode",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.10.0",
|
|
4
4
|
"description": "Loki Mode by Autonomi. Autonomous spec-to-product system: takes a PRD, GitHub issue, OpenAPI/JSON/YAML, or one-line brief to a deployed app via the RARV-C closure loop with 11 quality gates. Provider-agnostic (Claude Code, OpenAI Codex, Cline, Aider).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|