loki-mode 7.93.0 → 7.95.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/done-recognition.sh +823 -0
- package/autonomy/run.sh +98 -1
- package/dashboard/__init__.py +1 -1
- package/docs/INSTALLATION.md +1 -1
- package/docs/PRD-REUSE-DONE-RECOGNITION-PLAN.md +536 -0
- 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/autonomy/run.sh
CHANGED
|
@@ -13383,7 +13383,7 @@ except (json.JSONDecodeError, KeyError, TypeError, OSError):
|
|
|
13383
13383
|
ITERATION_COUNT=0
|
|
13384
13384
|
fi
|
|
13385
13385
|
;;
|
|
13386
|
-
failed|max_iterations_reached|max_retries_exceeded|exited|council_approved|council_force_approved|completion_promise_fulfilled)
|
|
13386
|
+
failed|max_iterations_reached|max_retries_exceeded|exited|council_approved|council_force_approved|completion_promise_fulfilled|reuse_already_satisfied)
|
|
13387
13387
|
log_info "Previous session ended with status: $prev_status. Resetting for new session."
|
|
13388
13388
|
RETRY_COUNT=0
|
|
13389
13389
|
ITERATION_COUNT=0
|
|
@@ -14859,6 +14859,40 @@ if os.path.exists(pending_path):
|
|
|
14859
14859
|
existing_ids = {t.get("id") for t in existing if isinstance(t, dict)}
|
|
14860
14860
|
added = 0
|
|
14861
14861
|
|
|
14862
|
+
# Reuse done-recognition (v7.94.0): if a satisfied-requirements manifest exists
|
|
14863
|
+
# AND its prd_sha matches THIS PRD's hash, skip any feature whose title is
|
|
14864
|
+
# already satisfied, so an incremental reuse run rebuilds ONLY the gap. A stale
|
|
14865
|
+
# or absent manifest is ignored (full build -- the safe default). The sha is
|
|
14866
|
+
# computed over the SAME PRD file bytes the gate hashed (hashlib.sha256), so the
|
|
14867
|
+
# guard matches byte-for-byte. Title match is normalized (case-insensitive, with
|
|
14868
|
+
# a leading "feature:/requirement:/epic:/story:" heading prefix stripped) so a
|
|
14869
|
+
# model-returned title like "User login" matches the parser's heading title
|
|
14870
|
+
# "Feature: User login". bash 3.2 safe: all normalization happens in python.
|
|
14871
|
+
def _dr_norm_title(s):
|
|
14872
|
+
s = (s or "").strip().lower()
|
|
14873
|
+
for _pfx in ("feature:", "requirement:", "epic:", "story:", "user story:"):
|
|
14874
|
+
if s.startswith(_pfx):
|
|
14875
|
+
s = s[len(_pfx):].strip()
|
|
14876
|
+
break
|
|
14877
|
+
return s
|
|
14878
|
+
|
|
14879
|
+
_dr_satisfied = set()
|
|
14880
|
+
try:
|
|
14881
|
+
import hashlib
|
|
14882
|
+
_dr_manifest = ".loki/state/satisfied-requirements.json"
|
|
14883
|
+
if os.path.isfile(_dr_manifest):
|
|
14884
|
+
with open(_dr_manifest, "r") as _mf:
|
|
14885
|
+
_dr_data = json.load(_mf)
|
|
14886
|
+
_dr_manifest_sha = (_dr_data.get("prd_sha") or "").strip()
|
|
14887
|
+
with open(prd_path, "rb") as _pf:
|
|
14888
|
+
_dr_cur_sha = hashlib.sha256(_pf.read()).hexdigest()
|
|
14889
|
+
if _dr_manifest_sha and _dr_manifest_sha == _dr_cur_sha:
|
|
14890
|
+
for _t in _dr_data.get("satisfied", []):
|
|
14891
|
+
if isinstance(_t, str) and _t.strip():
|
|
14892
|
+
_dr_satisfied.add(_dr_norm_title(_t))
|
|
14893
|
+
except Exception:
|
|
14894
|
+
_dr_satisfied = set()
|
|
14895
|
+
|
|
14862
14896
|
# BUG-V63-001 fix: extract audience once with flag to break both loops
|
|
14863
14897
|
audience = "a user"
|
|
14864
14898
|
audience_found = False
|
|
@@ -14878,6 +14912,12 @@ for i, feat in enumerate(features):
|
|
|
14878
14912
|
if task_id in existing_ids:
|
|
14879
14913
|
continue
|
|
14880
14914
|
|
|
14915
|
+
# Skip features the done-recognition gate verified as already satisfied
|
|
14916
|
+
# (manifest-driven, title-keyed, normalized match). Only unmet requirements
|
|
14917
|
+
# become tasks, so the RARV loop works only the gap.
|
|
14918
|
+
if _dr_satisfied and _dr_norm_title(feat.get("title")) in _dr_satisfied:
|
|
14919
|
+
continue
|
|
14920
|
+
|
|
14881
14921
|
criteria = extract_acceptance_criteria(feat["section"], sections)
|
|
14882
14922
|
|
|
14883
14923
|
# Build a rich description
|
|
@@ -15238,6 +15278,39 @@ except Exception:
|
|
|
15238
15278
|
load_state
|
|
15239
15279
|
local retry=$RETRY_COUNT
|
|
15240
15280
|
|
|
15281
|
+
# Reuse done-recognition gate (v7.94.0). On a no-PRD run that is REUSING an
|
|
15282
|
+
# already-generated PRD, model-verify whether the codebase already satisfies
|
|
15283
|
+
# that spec BEFORE rebuilding a task queue and re-running the RARV loop.
|
|
15284
|
+
# Routes to one of three outcomes (the verdict is the model's, grounded in
|
|
15285
|
+
# re-run tests + code; the only deterministic shortcut is NEGATIVE -> build):
|
|
15286
|
+
# done -> refresh the verified-completion record, finalize, return 0
|
|
15287
|
+
# so the queue/loop is skipped and main()'s terminal block
|
|
15288
|
+
# finishes the run (no wasted iterations, no stray delegate
|
|
15289
|
+
# branch -- this runs BEFORE the start-sha/delegate block).
|
|
15290
|
+
# incomplete -> write .loki/state/satisfied-requirements.json so
|
|
15291
|
+
# populate_prd_queue builds ONLY the unsatisfied items, then
|
|
15292
|
+
# fall through to the (now incremental) build.
|
|
15293
|
+
# inconclusive-> fall through to the normal full build (safe default).
|
|
15294
|
+
# Default-on; LOKI_DONE_RECOGNITION=0 disables it. Armed only on a reuse of
|
|
15295
|
+
# an existing generated PRD; `update` (stale PRD) may never fast-stop as done.
|
|
15296
|
+
case "${GENERATED_PRD_ACTION:-}" in
|
|
15297
|
+
reuse|user_owned|update)
|
|
15298
|
+
local _done_recog_lib="$SCRIPT_DIR/lib/done-recognition.sh"
|
|
15299
|
+
if [ -f "$_done_recog_lib" ]; then
|
|
15300
|
+
# shellcheck source=lib/done-recognition.sh
|
|
15301
|
+
source "$_done_recog_lib" 2>/dev/null || true
|
|
15302
|
+
if declare -f reuse_done_recognition_gate >/dev/null 2>&1; then
|
|
15303
|
+
if reuse_done_recognition_gate "$prd_path"; then
|
|
15304
|
+
# done verdict: the gate finalized; main()'s terminal
|
|
15305
|
+
# block (run_autonomous's caller) runs the COMPLETED
|
|
15306
|
+
# marker, proof-of-run, and HANDOFF.md.
|
|
15307
|
+
return 0
|
|
15308
|
+
fi
|
|
15309
|
+
fi
|
|
15310
|
+
fi
|
|
15311
|
+
;;
|
|
15312
|
+
esac
|
|
15313
|
+
|
|
15241
15314
|
# Capture run-start SHA for the evidence hard gate (v7.19.1).
|
|
15242
15315
|
# Fresh-run-aware: recapture HEAD when ITERATION_COUNT==0 (fresh invocation,
|
|
15243
15316
|
# reset, or corrupted/missing baseline); preserve only on a genuine resume
|
|
@@ -17077,6 +17150,30 @@ else:
|
|
|
17077
17150
|
if [ "$_completion_claimed" = 1 ] && type ensure_completion_test_evidence &>/dev/null; then
|
|
17078
17151
|
ensure_completion_test_evidence || true
|
|
17079
17152
|
fi
|
|
17153
|
+
# TRUST MOAT (fail-CLOSED): each completion gate below is armed only
|
|
17154
|
+
# when its function is loadable (`type fn && ! fn`). If the council
|
|
17155
|
+
# library failed to source, those `type` probes are FALSE, so every
|
|
17156
|
+
# gate arm is silently skipped and a completion claim sails straight to
|
|
17157
|
+
# the accept branch UNVERIFIED -- a fake-green. Before the gate chain,
|
|
17158
|
+
# verify the core gate functions exist; if any is missing, the library
|
|
17159
|
+
# is incomplete and we CANNOT verify completion, so we refuse the claim
|
|
17160
|
+
# (force another iteration) rather than pass ungated. This never fires
|
|
17161
|
+
# in a healthy install (functions are sourced) and only triggers on a
|
|
17162
|
+
# genuinely broken/partial load -- exactly when failing open is unsafe.
|
|
17163
|
+
if [ "$_completion_claimed" = 1 ]; then
|
|
17164
|
+
_gates_loadable=1
|
|
17165
|
+
for _gate_fn in council_checklist_gate council_evidence_gate council_heldout_gate council_assumption_ledger_gate; do
|
|
17166
|
+
if ! type "$_gate_fn" &>/dev/null; then
|
|
17167
|
+
log_error "Completion gate unavailable: ${_gate_fn} (council library incomplete or failed to load)."
|
|
17168
|
+
_gates_loadable=0
|
|
17169
|
+
fi
|
|
17170
|
+
done
|
|
17171
|
+
if [ "$_gates_loadable" -eq 0 ]; then
|
|
17172
|
+
log_error "Cannot verify completion: required council gates are missing. Refusing the completion claim (fail-closed) and continuing to iterate."
|
|
17173
|
+
_completion_claimed=0
|
|
17174
|
+
fi
|
|
17175
|
+
unset _gates_loadable _gate_fn
|
|
17176
|
+
fi
|
|
17080
17177
|
if [ -n "$_gate_block_for_completion" ] && [ "$_completion_claimed" = 1 ]; then
|
|
17081
17178
|
log_warn "Completion claim rejected: code review is BLOCKED for this iteration (Critical/High findings). Fix review issues before completion."
|
|
17082
17179
|
log_warn " Review details under .loki/quality/reviews/ ; gate_failures=${gate_failures}"
|
package/dashboard/__init__.py
CHANGED
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:** v7.
|
|
5
|
+
**Version:** v7.95.0
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|