loki-mode 9.26.3 → 9.27.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/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/lib/proof-generator.py +99 -0
- package/autonomy/lib/proof-template.html +51 -1
- package/autonomy/loki +20 -0
- package/dashboard/__init__.py +1 -1
- package/docs/COMPETITIVE-NEXT-10.md +60 -41
- 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/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
package/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: loki-mode
|
|
|
3
3
|
description: Autonomous spec-driven build system with a built-in trust layer. It does not call work done until it is verified (RARV-C closure loop, 8 quality gates, completion council, verified-completion evidence gate). Triggers on "Loki Mode". Takes a spec (PRD, GitHub issue, OpenAPI doc, etc.) to deployed product with minimal human intervention. Provider-agnostic. Requires --dangerously-skip-permissions flag.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Loki Mode v9.
|
|
6
|
+
# Loki Mode v9.27.1
|
|
7
7
|
|
|
8
8
|
**You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
|
|
9
9
|
|
|
@@ -470,4 +470,4 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
|
|
|
470
470
|
|
|
471
471
|
---
|
|
472
472
|
|
|
473
|
-
**v9.
|
|
473
|
+
**v9.27.1 | [Autonomi](https://www.autonomi.dev/) flagship product | ~410 lines core**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
9.
|
|
1
|
+
9.27.1
|
|
@@ -644,6 +644,66 @@ def _collect_model(loki_dir, observed):
|
|
|
644
644
|
return "unavailable"
|
|
645
645
|
|
|
646
646
|
|
|
647
|
+
def _collect_decisions(loki_dir):
|
|
648
|
+
"""Which models actually ran, and did the configuration change mid-flight?
|
|
649
|
+
|
|
650
|
+
Reads the append-only trail at .loki/decisions/decisions.jsonl that
|
|
651
|
+
autonomy/lib/decision_record.py writes once per dispatch. That module
|
|
652
|
+
already computes the audit fact worth showing -- more than one model_id in
|
|
653
|
+
one project means the deciding component changed while the run was in
|
|
654
|
+
flight -- so this reuses summarize() rather than recomputing it.
|
|
655
|
+
|
|
656
|
+
THREE STATES, NEVER COLLAPSED, for the same reason _collect_model returns
|
|
657
|
+
the literal "unavailable" instead of guessing:
|
|
658
|
+
|
|
659
|
+
measured -- records exist; counts and model_changed are real
|
|
660
|
+
no_records -- the trail is absent for this run
|
|
661
|
+
unreadable -- the trail exists but could not be read
|
|
662
|
+
|
|
663
|
+
A section that renders nothing when the trail is absent reads as "no swap
|
|
664
|
+
happened", which is exactly the false green this receipt exists to prevent.
|
|
665
|
+
Absence of evidence is reported as absence of evidence.
|
|
666
|
+
|
|
667
|
+
model_changed is a DISCLOSED FACT, not a failure. run.sh documents four
|
|
668
|
+
legitimate reasons a model changes mid-run (opus-pin force, LOKI_MAX_TIER
|
|
669
|
+
clamp, mid-flight override, fable collapse). It never touches the verdict.
|
|
670
|
+
|
|
671
|
+
Corrupt lines are surfaced via unparseable_lines rather than dropped: an
|
|
672
|
+
audit trail that quietly discards what it cannot parse is worse than one
|
|
673
|
+
that admits the gap.
|
|
674
|
+
"""
|
|
675
|
+
try:
|
|
676
|
+
from decision_record import summarize as _summarize
|
|
677
|
+
except ImportError:
|
|
678
|
+
return {"status": "unreadable", "reason": "decision_record module unavailable"}
|
|
679
|
+
|
|
680
|
+
try:
|
|
681
|
+
raw = _summarize(loki_dir)
|
|
682
|
+
except Exception as exc: # never let provenance reporting break the receipt
|
|
683
|
+
return {"status": "unreadable", "reason": str(exc)}
|
|
684
|
+
|
|
685
|
+
if not isinstance(raw, dict):
|
|
686
|
+
return {"status": "unreadable", "reason": "invalid summary"}
|
|
687
|
+
|
|
688
|
+
if raw.get("status") == "measured":
|
|
689
|
+
return {
|
|
690
|
+
"status": "measured",
|
|
691
|
+
"records": _to_int(raw.get("records"), 0),
|
|
692
|
+
"unparseable_lines": _to_int(raw.get("unparseable_lines"), 0),
|
|
693
|
+
"models": raw.get("models") or {},
|
|
694
|
+
"stages": raw.get("stages") or {},
|
|
695
|
+
"model_changed": bool(raw.get("model_changed")),
|
|
696
|
+
"temperature_changed": bool(raw.get("temperature_changed")),
|
|
697
|
+
# Never influences the verdict: this is provenance, not a gate.
|
|
698
|
+
"affects_verdict": False,
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
reason = str(raw.get("reason") or "unknown")
|
|
702
|
+
status = "no_records" if reason == "no_records" else "unreadable"
|
|
703
|
+
return {"status": status, "reason": reason,
|
|
704
|
+
"detail": str(raw.get("detail") or ""), "affects_verdict": False}
|
|
705
|
+
|
|
706
|
+
|
|
647
707
|
def _collect_security(loki_dir):
|
|
648
708
|
"""Read .loki/quality/security-findings.json (the secure-by-default gate).
|
|
649
709
|
|
|
@@ -1237,6 +1297,9 @@ def _build_proof(args, loki_dir, target_dir, repo_root):
|
|
|
1237
1297
|
termination = _collect_termination(loki_dir, args.session_exit_code)
|
|
1238
1298
|
tests = _collect_tests(loki_dir)
|
|
1239
1299
|
security = _collect_security(loki_dir)
|
|
1300
|
+
# Model provenance: which models actually ran, and did that change
|
|
1301
|
+
# mid-flight. Provenance only -- affects_verdict is False.
|
|
1302
|
+
decisions = _collect_decisions(loki_dir)
|
|
1240
1303
|
functional = _collect_functional(loki_dir) # FV-2 record-half: descriptive only
|
|
1241
1304
|
healthcheck = _collect_healthcheck(loki_dir) # Evidence Receipt record-half
|
|
1242
1305
|
evidence_gate = _collect_evidence_gate(loki_dir)
|
|
@@ -1429,6 +1492,7 @@ def _build_proof(args, loki_dir, target_dir, repo_root):
|
|
|
1429
1492
|
"diffs": diffs,
|
|
1430
1493
|
"council": council,
|
|
1431
1494
|
"quality_gates": quality_gates,
|
|
1495
|
+
"decisions": decisions,
|
|
1432
1496
|
"cost": cost,
|
|
1433
1497
|
"deployment": deployment,
|
|
1434
1498
|
# Typed compatibility mirror for consumers that do not traverse facts.
|
|
@@ -1815,6 +1879,41 @@ def _render_fallback_html(proof):
|
|
|
1815
1879
|
"who produced them, so this receipt trusts its generator. "
|
|
1816
1880
|
"To sign future receipts, set LOKI_PROOF_GPG_KEY to a gpg "
|
|
1817
1881
|
"key id (see docs/SIGNED-RECEIPTS.md).</p>")
|
|
1882
|
+
|
|
1883
|
+
# Model provenance, mirrored here for the same reason the signature row is:
|
|
1884
|
+
# this fallback "must not be quieter about provenance than the page it
|
|
1885
|
+
# stands in for". Three states, never collapsed -- an absent trail is
|
|
1886
|
+
# reported as absent, not rendered as silence that reads like "no change".
|
|
1887
|
+
dec = proof.get("decisions") or {}
|
|
1888
|
+
dstatus = dec.get("status")
|
|
1889
|
+
if dstatus == "measured":
|
|
1890
|
+
models = dec.get("models") or {}
|
|
1891
|
+
listing = ", ".join(
|
|
1892
|
+
"%s (%s)" % (esc(k2), esc(v2)) for k2, v2 in sorted(models.items())
|
|
1893
|
+
) or "none recorded"
|
|
1894
|
+
if dec.get("model_changed"):
|
|
1895
|
+
change = ("The model CHANGED during this run. That is disclosed, not a "
|
|
1896
|
+
"fault -- a tier clamp, an operator override or a mid-flight "
|
|
1897
|
+
"failover all cause it legitimately.")
|
|
1898
|
+
else:
|
|
1899
|
+
change = "One model ran for the whole project; no mid-flight change."
|
|
1900
|
+
bad = _to_int(dec.get("unparseable_lines"), 0)
|
|
1901
|
+
badnote = ""
|
|
1902
|
+
if bad > 0:
|
|
1903
|
+
badnote = (" %d trail line(s) could not be parsed and are counted "
|
|
1904
|
+
"rather than dropped, so the list may be incomplete." % bad)
|
|
1905
|
+
rows.append("<p>Models dispatched (append-only decision trail): %s. %s%s "
|
|
1906
|
+
"Provenance only; never changes the verdict.</p>"
|
|
1907
|
+
% (listing, change, badnote))
|
|
1908
|
+
elif dstatus == "no_records":
|
|
1909
|
+
rows.append("<p>Models dispatched: no decision trail was recorded for this "
|
|
1910
|
+
"run, so per-iteration model attribution cannot be confirmed. "
|
|
1911
|
+
"Absence of the trail is reported as absence of evidence, not "
|
|
1912
|
+
"as proof that nothing changed.</p>")
|
|
1913
|
+
elif dstatus:
|
|
1914
|
+
rows.append("<p>Models dispatched: the decision trail could not be read "
|
|
1915
|
+
"(%s), so per-iteration model attribution is unavailable. "
|
|
1916
|
+
"Reported rather than omitted.</p>" % esc(dec.get("reason", "unknown")))
|
|
1818
1917
|
red = proof.get("redaction", {})
|
|
1819
1918
|
rows.append("<p>Redaction applied: %s (%s redactions, rules v%s)</p>" % (
|
|
1820
1919
|
esc(red.get("applied")), esc(red.get("redactions_count")),
|
|
@@ -1268,10 +1268,60 @@
|
|
|
1268
1268
|
var signNote = signed
|
|
1269
1269
|
? '<p class="hash-note">This receipt carries a detached GPG signature over the same canonical bytes that were hashed. A verifier holding the signer public key can confirm its provenance offline with <code>loki proof verify</code>.</p>'
|
|
1270
1270
|
: '<p class="hash-note">This receipt is UNSIGNED, so it trusts the generator that produced it (<code>loki proof verify</code> reports <code>generator_trusted: true</code>). To sign future receipts, set <code>LOKI_PROOF_GPG_KEY</code> to a GPG key id before the run.</p>';
|
|
1271
|
+
// Model provenance from the append-only decision trail
|
|
1272
|
+
// (.loki/decisions/decisions.jsonl, written once per dispatch).
|
|
1273
|
+
//
|
|
1274
|
+
// The "Model" row above is the run-level model. It cannot answer the
|
|
1275
|
+
// question a regulated buyer actually asks: did the deciding component
|
|
1276
|
+
// change while the run was in flight? Two model ids in one project is
|
|
1277
|
+
// exactly that case, and the trail proves it either way.
|
|
1278
|
+
//
|
|
1279
|
+
// THREE STATES, NEVER COLLAPSED. A section that renders nothing when the
|
|
1280
|
+
// trail is absent reads as "no swap happened" -- the false green this
|
|
1281
|
+
// receipt exists to prevent. An older receipt predating this field has no
|
|
1282
|
+
// "decisions" key at all and is left silent rather than described, since a
|
|
1283
|
+
// receipt that never recorded the trail cannot honestly report on it.
|
|
1284
|
+
var dec = g(p, "decisions", null);
|
|
1285
|
+
var decNote = "";
|
|
1286
|
+
if (dec && g(dec, "status", "")) {
|
|
1287
|
+
var dstatus = g(dec, "status", "");
|
|
1288
|
+
if (dstatus === "measured") {
|
|
1289
|
+
var models = g(dec, "models", {}) || {};
|
|
1290
|
+
var names = [];
|
|
1291
|
+
for (var mk in models) {
|
|
1292
|
+
if (Object.prototype.hasOwnProperty.call(models, mk)) {
|
|
1293
|
+
names.push(esc(mk) + " (" + num(models[mk]) + ")");
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
var changed = !!g(dec, "model_changed", false);
|
|
1297
|
+
var bad = num(g(dec, "unparseable_lines", 0));
|
|
1298
|
+
decNote = '<p class="hash-note">Models dispatched, from the run\u2019s own ' +
|
|
1299
|
+
"append-only decision trail: " + (names.length ? names.join(", ") : "none recorded") +
|
|
1300
|
+
". " +
|
|
1301
|
+
(changed
|
|
1302
|
+
? "The model CHANGED during this run. That is disclosed, not a fault -- a tier clamp, an " +
|
|
1303
|
+
"operator override or a mid-flight failover all cause it legitimately -- but it is the " +
|
|
1304
|
+
"thing you would otherwise have to take on trust."
|
|
1305
|
+
: "One model ran for the whole project; the trail shows no mid-flight change.") +
|
|
1306
|
+
(bad > 0
|
|
1307
|
+
? " " + bad + " line" + (bad === 1 ? "" : "s") + " of the trail could not be parsed and " +
|
|
1308
|
+
"are counted here rather than dropped, so this list may be incomplete."
|
|
1309
|
+
: "") +
|
|
1310
|
+
" This is provenance and never changes the verdict.</p>";
|
|
1311
|
+
} else if (dstatus === "no_records") {
|
|
1312
|
+
decNote = '<p class="hash-note">No decision trail was recorded for this run, so which ' +
|
|
1313
|
+
"model served each iteration cannot be confirmed from this receipt. Absence of the trail " +
|
|
1314
|
+
"is reported as absence of evidence, not as proof that nothing changed.</p>";
|
|
1315
|
+
} else {
|
|
1316
|
+
decNote = '<p class="hash-note">The decision trail for this run could not be read (' +
|
|
1317
|
+
esc(g(dec, "reason", "unknown")) + "), so per-iteration model attribution is unavailable. " +
|
|
1318
|
+
"Reported rather than omitted.</p>";
|
|
1319
|
+
}
|
|
1320
|
+
}
|
|
1271
1321
|
card.innerHTML = '<div class="kv">' + kv + "</div>" +
|
|
1272
1322
|
(hash ? '<p class="hash-note">The integrity hash is a ' + esc(algo) +
|
|
1273
1323
|
" digest of this proof. It proves the artifact has not been altered after it was emitted. It does not, by itself, prove who or what produced the work.</p>" : "") +
|
|
1274
|
-
signNote;
|
|
1324
|
+
signNote + decNote;
|
|
1275
1325
|
}
|
|
1276
1326
|
|
|
1277
1327
|
function renderCta(p) {
|
package/autonomy/loki
CHANGED
|
@@ -2148,6 +2148,26 @@ cmd_start() {
|
|
|
2148
2148
|
echo " loki start --yes # Skip confirmation prompt"
|
|
2149
2149
|
echo " LOKI_PRD_FILE=./prd.md loki start # PRD via env var"
|
|
2150
2150
|
echo ""
|
|
2151
|
+
# Exit codes, stated where a CI author actually looks. The full
|
|
2152
|
+
# contract lived only in docs/exit-codes.md, so a script author
|
|
2153
|
+
# read this help, saw nothing, and built the coarse gate -- the
|
|
2154
|
+
# tiered contract might as well not have shipped.
|
|
2155
|
+
echo "Exit codes:"
|
|
2156
|
+
echo " 0 The run completed, or a human stopped it"
|
|
2157
|
+
echo " nonzero Something went wrong (no finer signal by default)"
|
|
2158
|
+
echo ""
|
|
2159
|
+
echo " With LOKI_DURABLE_STATE=1 the platform contract applies, which"
|
|
2160
|
+
echo " distinguishes 'retrying cannot help' from 'the process died':"
|
|
2161
|
+
echo " 0 Completed, or a human stopped it -> do not retry"
|
|
2162
|
+
echo " 20 Deterministic terminal failure (gate failed, max"
|
|
2163
|
+
echo " iterations or retries, budget or wall-clock cap,"
|
|
2164
|
+
echo " policy block, contradictory spec) -> do not retry;"
|
|
2165
|
+
echo " the same inputs fail the same way"
|
|
2166
|
+
echo " other nonzero Crash (SIGKILL, eviction, node loss) -> retry;"
|
|
2167
|
+
echo " the run resumes from the durable volume"
|
|
2168
|
+
echo " Both the bash and Bun runners implement this identically."
|
|
2169
|
+
echo " Full table, including loki verify and loki ci: docs/exit-codes.md"
|
|
2170
|
+
echo ""
|
|
2151
2171
|
echo "Note: 'loki run' is a deprecated alias for 'loki start' with an issue ref."
|
|
2152
2172
|
exit 0
|
|
2153
2173
|
;;
|
package/dashboard/__init__.py
CHANGED
|
@@ -24,32 +24,32 @@ one strengthens a claim a buyer can verify without trusting us.
|
|
|
24
24
|
|
|
25
25
|
---
|
|
26
26
|
|
|
27
|
-
## 1.
|
|
28
|
-
|
|
29
|
-
**
|
|
30
|
-
|
|
31
|
-
`
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
27
|
+
## 1. Model provenance on the receipt -- SHIPPED v9.27.0
|
|
28
|
+
|
|
29
|
+
**Corrected.** An earlier draft of this item claimed the exogenous/advisory gate
|
|
30
|
+
split, files-changed and cost "do not reach the top of the receipt". That was
|
|
31
|
+
wrong, and reading the renderers disproved it: `proof-template.html:1165-1192`
|
|
32
|
+
already renders the split with the strongest honesty framing in the repo
|
|
33
|
+
("a model that is confidently wrong scores itself green here"), plus
|
|
34
|
+
disabled-gate disclosure, cost, tokens, wall clock and files changed.
|
|
35
|
+
|
|
36
|
+
Five of the six fields were already shipped. **One was genuinely missing:**
|
|
37
|
+
per-iteration model attribution. `autonomy/lib/decision_record.py` writes an
|
|
38
|
+
append-only trail to `.loki/decisions/decisions.jsonl` once per dispatch, and
|
|
39
|
+
already computes the audit fact worth showing -- `model_changed`, meaning more
|
|
40
|
+
than one model id served one project. The proof generator read that file
|
|
41
|
+
**zero times**.
|
|
42
|
+
|
|
43
|
+
That is the question a regulated buyer actually asks, and the one Factory users
|
|
44
|
+
complain about: did the deciding component change mid-run without anyone saying
|
|
45
|
+
so? The run-level "Model" row cannot answer it.
|
|
46
|
+
|
|
47
|
+
**Shipped in v9.27.0** in both renderers, with three states never collapsed --
|
|
48
|
+
`measured`, `no_records`, `unreadable`. An absent trail is reported as absent
|
|
49
|
+
rather than rendered as silence that reads like "no swap happened", corrupt
|
|
50
|
+
trail lines are counted rather than dropped, and `affects_verdict` is `false`:
|
|
51
|
+
a mid-flight change is a disclosed fact (tier clamp, operator override,
|
|
52
|
+
failover all cause it legitimately), never a fault and never a verdict input.
|
|
53
53
|
|
|
54
54
|
## 2. Make the machine contract discoverable
|
|
55
55
|
|
|
@@ -66,8 +66,16 @@ A CI author reads `--help`, sees "0 on success, nonzero on failure", and builds
|
|
|
66
66
|
the coarse gate. Factory's `droid exec` advertises its exit codes in its own help
|
|
67
67
|
output; ours are a doc you have to already know exists.
|
|
68
68
|
|
|
69
|
-
**
|
|
70
|
-
|
|
69
|
+
**Shipped in v9.27.1** for `loki start --help`: the two-tier contract, code 20,
|
|
70
|
+
its retry semantics, and a pointer to `docs/exit-codes.md`. A drift assertion
|
|
71
|
+
fails if the code stated in the help stops matching the code in the doc, since
|
|
72
|
+
two documents disagreeing about a value a Kubernetes Job is configured on is
|
|
73
|
+
worse than one.
|
|
74
|
+
|
|
75
|
+
`loki verify --help` needed no change -- it already carried an `EXIT CODES`
|
|
76
|
+
section. Adding a second one (which I briefly did) would have created exactly
|
|
77
|
+
the duplicated-and-drifting help this item exists to prevent; a test now asserts
|
|
78
|
+
there is exactly one.
|
|
71
79
|
|
|
72
80
|
**Note:** the research framed this as "Loki has no headless one-shot contract".
|
|
73
81
|
That framing was wrong -- the contract exists. The defect is discoverability,
|
|
@@ -97,17 +105,22 @@ of the time is worse than no number.
|
|
|
97
105
|
|
|
98
106
|
## 4. Close the config-diagnostic gap for the remaining format
|
|
99
107
|
|
|
100
|
-
**Status: shipped for JSON and .
|
|
108
|
+
**Status: shipped for JSON, `.env`, and YAML. Narrow residual gap only.**
|
|
109
|
+
|
|
110
|
+
`loki config validate` reports unknown keys in JSON and `.env` (v9.26.1) and in
|
|
111
|
+
YAML via pyyaml with a `yq` fallback (v9.26.2). `yq` is preinstalled on the
|
|
112
|
+
GitHub ubuntu-24.04 runner, and the fallback was verified against a stand-in
|
|
113
|
+
honouring both invocation shapes the real `yq` is called with, so CI and any
|
|
114
|
+
Linux host with either parser get full detection.
|
|
101
115
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
detection.
|
|
116
|
+
The residual gap is narrow: a host with **neither** pyyaml nor `yq` (a stock
|
|
117
|
+
macOS dev machine) gets no YAML detection. It degrades quietly, which is correct
|
|
118
|
+
-- a missing parser must never invent a verdict -- but silently.
|
|
106
119
|
|
|
107
|
-
**Do:**
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
120
|
+
**Do:** state the dependency in `loki config validate --help` so the gap is
|
|
121
|
+
visible rather than silent. Vendoring a YAML scanner is not worth it for one
|
|
122
|
+
host shape that already has a documented fallback available via `brew install
|
|
123
|
+
yq`.
|
|
111
124
|
|
|
112
125
|
---
|
|
113
126
|
|
|
@@ -160,10 +173,16 @@ before every push. v9.26.0 failed the same way on repo-wide ShellCheck.
|
|
|
160
173
|
CLAUDE.md already states the rule ("a check that guards the shipped artifact must
|
|
161
174
|
run in the FAST tier"). The rule is not enforced.
|
|
162
175
|
|
|
163
|
-
**
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
176
|
+
**Shipped in v9.26.3** as `scripts/guard-changed.sh`: runs the suites that
|
|
177
|
+
reference the files in your diff, plus ShellCheck on the changed shell files.
|
|
178
|
+
Measured 8s for a one-file change, ~135s worst case, against 26m50s for the FULL
|
|
179
|
+
tier. Verified it would have blocked the v9.26.0 push locally.
|
|
180
|
+
|
|
181
|
+
**Remaining:** it is necessary, not sufficient. It cannot catch a failure that
|
|
182
|
+
depends on CI differing from your machine -- which is exactly how v9.26.2 failed,
|
|
183
|
+
on a suite this script selects and runs. The follow-on work is making
|
|
184
|
+
environment-conditional assertions name their condition (`command -v yq`) rather
|
|
185
|
+
than assume the author's host. That is a review habit, not a script.
|
|
167
186
|
|
|
168
187
|
---
|
|
169
188
|
|
package/docs/INSTALLATION.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
The flagship product of [Autonomi](https://www.autonomi.dev/). Loki Mode is a spec-driven autonomous builder with a built-in trust layer that takes any spec to a deployed product and verifies completion with evidence (quality gates plus a completion council), not just a "done" claim. Complete installation instructions for all platforms and use cases.
|
|
4
4
|
|
|
5
|
-
**Version:** v9.
|
|
5
|
+
**Version:** v9.27.1
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
package/loki-ts/dist/loki.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var St=Object.create;var{getPrototypeOf:yt,defineProperty:jG,getOwnPropertyNames:bt}=Object;var ft=Object.prototype.hasOwnProperty;function _t($){return this[$]}var vt,ht,gt=($,X,Q)=>{var z=$!=null&&typeof $==="object";if(z){var Z=X?vt??=new WeakMap:ht??=new WeakMap,K=Z.get($);if(K)return K}Q=$!=null?St(yt($)):{};let J=X||!$||!$.__esModule?jG(Q,"default",{value:$,enumerable:!0}):Q;for(let q of bt($))if(!ft.call(J,q))jG(J,q,{get:_t.bind($,q),enumerable:!0});if(z)Z.set($,J);return J};var zq=($,X)=>()=>(X||$((X={exports:{}}).exports,X),X.exports);var mt=($)=>$;function ut($,X){this[$]=mt.bind(null,X)}var B1=($,X)=>{for(var Q in X)jG($,Q,{get:X[Q],enumerable:!0,configurable:!0,set:ut.bind(X,Q)})};var s=($,X)=>()=>($&&(X=$($=0)),X);var w5=import.meta.require;var YR={};B1(YR,{lokiDir:()=>h0,homeLokiDir:()=>HQ,findRepoRootForVersion:()=>AG,REPO_ROOT:()=>L1});import{resolve as h2,dirname as LG}from"path";import{fileURLToPath as dt}from"url";import{existsSync as Zq}from"fs";import{homedir as pt}from"os";function ct(){let $=VR;for(let X=0;X<6;X++){if(Zq(h2($,"VERSION"))&&Zq(h2($,"autonomy/run.sh")))return $;let Q=LG($);if(Q===$)break;$=Q}return h2(VR,"..","..","..")}function AG($){let X=$;for(let Q=0;Q<6;Q++){if(Zq(h2(X,"VERSION"))&&Zq(h2(X,"autonomy/run.sh")))return X;let z=LG(X);if(z===X)break;X=z}return h2($,"..","..","..")}function h0(){return process.env.LOKI_DIR??h2(process.cwd(),".loki")}function HQ(){return h2(pt(),".loki")}var VR,L1;var k1=s(()=>{VR=LG(dt(import.meta.url));L1=ct()});import{readFileSync as lt}from"fs";import{resolve as it,dirname as at}from"path";import{fileURLToPath as ot}from"url";function j9(){if(n3!==null)return n3;let $="9.
|
|
2
|
+
var St=Object.create;var{getPrototypeOf:yt,defineProperty:jG,getOwnPropertyNames:bt}=Object;var ft=Object.prototype.hasOwnProperty;function _t($){return this[$]}var vt,ht,gt=($,X,Q)=>{var z=$!=null&&typeof $==="object";if(z){var Z=X?vt??=new WeakMap:ht??=new WeakMap,K=Z.get($);if(K)return K}Q=$!=null?St(yt($)):{};let J=X||!$||!$.__esModule?jG(Q,"default",{value:$,enumerable:!0}):Q;for(let q of bt($))if(!ft.call(J,q))jG(J,q,{get:_t.bind($,q),enumerable:!0});if(z)Z.set($,J);return J};var zq=($,X)=>()=>(X||$((X={exports:{}}).exports,X),X.exports);var mt=($)=>$;function ut($,X){this[$]=mt.bind(null,X)}var B1=($,X)=>{for(var Q in X)jG($,Q,{get:X[Q],enumerable:!0,configurable:!0,set:ut.bind(X,Q)})};var s=($,X)=>()=>($&&(X=$($=0)),X);var w5=import.meta.require;var YR={};B1(YR,{lokiDir:()=>h0,homeLokiDir:()=>HQ,findRepoRootForVersion:()=>AG,REPO_ROOT:()=>L1});import{resolve as h2,dirname as LG}from"path";import{fileURLToPath as dt}from"url";import{existsSync as Zq}from"fs";import{homedir as pt}from"os";function ct(){let $=VR;for(let X=0;X<6;X++){if(Zq(h2($,"VERSION"))&&Zq(h2($,"autonomy/run.sh")))return $;let Q=LG($);if(Q===$)break;$=Q}return h2(VR,"..","..","..")}function AG($){let X=$;for(let Q=0;Q<6;Q++){if(Zq(h2(X,"VERSION"))&&Zq(h2(X,"autonomy/run.sh")))return X;let z=LG(X);if(z===X)break;X=z}return h2($,"..","..","..")}function h0(){return process.env.LOKI_DIR??h2(process.cwd(),".loki")}function HQ(){return h2(pt(),".loki")}var VR,L1;var k1=s(()=>{VR=LG(dt(import.meta.url));L1=ct()});import{readFileSync as lt}from"fs";import{resolve as it,dirname as at}from"path";import{fileURLToPath as ot}from"url";function j9(){if(n3!==null)return n3;let $="9.27.1";if(typeof $==="string"&&$.length>0)return n3=$,n3;try{let X=at(ot(import.meta.url)),Q=AG(X);n3=lt(it(Q,"VERSION"),"utf-8").trim()}catch{n3="unknown"}return n3}var n3=null;var Kq=s(()=>{k1()});var GR={};B1(GR,{runOrThrow:()=>Ue,run:()=>$1,readStreamCapped:()=>Jq,commandVersion:()=>We,commandExists:()=>g5,ShellError:()=>CG,MAX_STDOUT_BYTES:()=>WR});async function Jq($,X=WR){let Q=$.getReader(),z=new TextDecoder,Z="",K=0;try{while(K<X){let{done:J,value:q}=await Q.read();if(J)break;if(!q)continue;if(K+=q.byteLength,K>X){let V=q.byteLength-(K-X);Z+=z.decode(q.subarray(0,V),{stream:!0});break}Z+=z.decode(q,{stream:!0})}Z+=z.decode()}finally{try{await Q.cancel()}catch{}Q.releaseLock()}return Z}async function $1($,X={}){let Q=Bun.spawn({cmd:[...$],stdout:"pipe",stderr:"pipe",env:X.env?{...process.env,...X.env}:process.env,cwd:X.cwd}),z,Z;if(X.timeoutMs&&X.timeoutMs>0)z=setTimeout(()=>{try{Q.kill("SIGTERM")}catch{}Z=setTimeout(()=>{try{Q.kill("SIGKILL")}catch{}},2000)},X.timeoutMs);try{let[K,J,q]=await Promise.all([Jq(Q.stdout),new Response(Q.stderr).text(),Q.exited]);return{stdout:K,stderr:J,exitCode:q}}finally{if(z)clearTimeout(z);if(Z)clearTimeout(Z)}}async function Ue($,X={}){let Q=await $1($,X);if(Q.exitCode!==0)throw new CG(`command failed (${Q.exitCode}): ${$.join(" ")}`,Q.exitCode,Q.stdout,Q.stderr);return Q}async function g5($){let X=He($),Q=await $1(["sh","-c",`command -v ${X}`],{timeoutMs:5000});if(Q.exitCode===0)return Q.stdout.trim()||null;return null}function He($){if(!/^[A-Za-z0-9._/-]+$/.test($))throw Error(`refused to shell-escape suspect token: ${$}`);return $}async function We($,X="--version"){if(!await g5($))return null;let z=await $1([$,X],{timeoutMs:5000});if(z.exitCode!==0)return null;return((z.stdout||z.stderr).split(/\r?\n/)[0]?.trim()??"")||null}var WR=16777216,CG;var y8=s(()=>{CG=class CG extends Error{message;exitCode;stdout;stderr;constructor($,X,Q,z){super($);this.message=$;this.exitCode=X;this.stdout=Q;this.stderr=z;this.name="ShellError"}}});function g2($){return Ge?"":$}var Ge,p0,$5,q1,L61,A1,f1,m5,r;var t7=s(()=>{Ge=(process.env.NO_COLOR??"").length>0;p0=g2("\x1B[0;31m"),$5=g2("\x1B[0;32m"),q1=g2("\x1B[1;33m"),L61=g2("\x1B[0;34m"),A1=g2("\x1B[0;36m"),f1=g2("\x1B[1m"),m5=g2("\x1B[2m"),r=g2("\x1B[0m")});import{existsSync as De}from"fs";async function Z2(){if(GQ!==void 0)return GQ;let $="/opt/homebrew/bin/python3.12";if(De($))return GQ=$,$;let X=await g5("python3.12");if(X)return GQ=X,X;let Q=await g5("python3");return GQ=Q,Q}async function I4($,X={}){let Q=await Z2();if(!Q)return{stdout:"",stderr:"python3 not found",exitCode:127};return $1([Q,"-c",$],X)}var GQ;var m2=s(()=>{y8()});var yR={};B1(yR,{runStatus:()=>oe});import{existsSync as u5,readFileSync as A9,readdirSync as RR,statSync as IR}from"fs";import{resolve as A5,basename as ge}from"path";import{homedir as me}from"os";function wR($){let X=Math.trunc($);if(X>=1e6)return`${(Math.trunc(X/1e6*10)/10).toFixed(1)}M`;if(X>=1000)return`${(Math.trunc(X/1000*10)/10).toFixed(1)}K`;return String(X)}function PR($,X,Q){if(X===0)return null;let z=Math.trunc($*100/X),Z=Math.trunc($*Vq/X);if(Z>Vq)Z=Vq;let K=Vq-Z,J=$5;if(z>=80)J=p0;else if(z>=50)J=q1;let q="=".repeat(Math.max(0,Z))+" ".repeat(Math.max(0,K)),V=wR($),Y=wR(X);return` ${f1}${Q}${r} ${J}[${q}]${r} ${z}% (${V} / ${Y})`}async function de(){if(await g5("jq"))return!0;return process.stdout.write(`${p0}Error: jq is required but not installed.${r}
|
|
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)
|
|
@@ -1334,4 +1334,4 @@ Set LOKI_LEGACY_BASH=1 to force the bash CLI for every command.
|
|
|
1334
1334
|
`),2}case"start":{let{runStart:z}=await Promise.resolve().then(() => (Et(),Pt));return z(Q)}default:return process.stderr.write(`Unknown command: ${X}
|
|
1335
1335
|
`),process.stderr.write(xt),2}}DR();process.on("SIGINT",()=>process.exit(130));process.on("SIGTERM",()=>process.exit(143));var X61=await $61(Bun.argv.slice(2));process.exit(X61);
|
|
1336
1336
|
|
|
1337
|
-
//# debugId=
|
|
1337
|
+
//# debugId=C762269CBE59DB093F45DC7B1E7F30AF
|
package/mcp/__init__.py
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "loki-mode",
|
|
3
3
|
"mcpName": "io.github.asklokesh/loki-mode",
|
|
4
|
-
"version": "9.
|
|
4
|
+
"version": "9.27.1",
|
|
5
5
|
"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 8 quality gates. Provider-agnostic (Claude Code, OpenAI Codex, Cline, Aider, opencode).",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"agent",
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
|
|
3
3
|
"name": "loki-mode",
|
|
4
4
|
"displayName": "Loki Mode",
|
|
5
|
-
"version": "9.
|
|
5
|
+
"version": "9.27.1",
|
|
6
6
|
"description": "Autonomous spec-to-product build system with a built-in trust layer (RARV-C closure loop, 8 quality gates, completion council). Ships Loki's spec-hardening, drift-detection, and deterministic PR verification commands plus the Loki MCP server.",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "Autonomi",
|