loki-mode 9.55.0 → 9.56.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/.github/actions/issue-to-pr/action.yml +165 -29
- package/.github/workflows/loki-issue-to-pr.yml +137 -24
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/lib/proof-check.sh +9 -0
- package/autonomy/lib/proof-generator.py +12 -3
- package/autonomy/lib/workspace_diff.py +18 -7
- package/autonomy/loki +133 -3
- package/autonomy/run.sh +363 -19
- package/dashboard/__init__.py +1 -1
- package/dashboard/api_keys.py +12 -5
- package/dashboard/build_supervisor.py +25 -1
- package/dashboard/server.py +46 -24
- package/dashboard/static/index.html +57 -57
- package/docs/VERIFIED-COMPLETION-PLAN.md +7 -5
- package/docs/environment-variables.md +1 -0
- package/docs/v10/BACKLOG.md +33 -0
- package/docs/v10/BOARD.md +67 -10
- package/docs/v10/DECISIONS.md +43 -0
- package/docs/v10/PROGRESS.md +731 -0
- package/loki-ts/dist/loki.js +326 -325
- package/mcp/__init__.py +1 -1
- package/package.json +1 -1
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/providers/claude.sh +1 -1
- package/providers/model_catalog.json +12 -5
- package/providers/models.sh +1 -1
- package/references/core-workflow.md +1 -1
- package/web-app/dist/assets/{AdminPage-CZrBkzRF.js → AdminPage-Oyx-w2Ch.js} +1 -1
- package/web-app/dist/assets/{Avatar-gQIp6FBI.js → Avatar-D60m65JB.js} +1 -1
- package/web-app/dist/assets/{Badge-D2_fBTFY.js → Badge-CqfZNaem.js} +1 -1
- package/web-app/dist/assets/{Button-D5qDd2ef.js → Button-BqjzE4fz.js} +1 -1
- package/web-app/dist/assets/CockpitPage-Czk7o_ou.js +47 -0
- package/web-app/dist/assets/ComparePage-BEfTrTb1.js +1 -0
- package/web-app/dist/assets/{ErrorBoundary-BRABI-BT.js → ErrorBoundary-BrLk5nkO.js} +1 -1
- package/web-app/dist/assets/EvidenceReceiptPanel-9vEpi5ir.js +1 -0
- package/web-app/dist/assets/{GitHubIssuesPanel-BC5GzKUN.js → GitHubIssuesPanel-D6izZx0w.js} +1 -1
- package/web-app/dist/assets/GitHubPRsPanel-BTkG2FgA.js +17 -0
- package/web-app/dist/assets/{HomePage-D_CDMoen.js → HomePage-nsr4kpN1.js} +2 -2
- package/web-app/dist/assets/{LoginPage-BBNA_N9t.js → LoginPage-BVblQrr9.js} +1 -1
- package/web-app/dist/assets/{MagicPage-CnFRZCMx.js → MagicPage-CmnSyLq7.js} +1 -1
- package/web-app/dist/assets/{MetricsPage-CPfLMRlh.js → MetricsPage-BVfwU81j.js} +1 -1
- package/web-app/dist/assets/{NotFoundPage-lA0XSGTz.js → NotFoundPage-AYQ6uqqI.js} +1 -1
- package/web-app/dist/assets/{ProjectPage-CNAPbr9z.js → ProjectPage-DMnbw9X9.js} +3 -3
- package/web-app/dist/assets/{ProjectsPage-CMtm8goN.js → ProjectsPage-CNVTAF2N.js} +1 -1
- package/web-app/dist/assets/{SettingsPage-BhIjVMYE.js → SettingsPage-D1_qasFD.js} +3 -3
- package/web-app/dist/assets/{ShowcasePage-BndtGeYo.js → ShowcasePage-2dBCjLXn.js} +1 -1
- package/web-app/dist/assets/{SystemSettingsPage-euXI-KXE.js → SystemSettingsPage-Djo6IE4u.js} +1 -1
- package/web-app/dist/assets/{TeamsPage-ClUKecun.js → TeamsPage-CY8p-yxD.js} +1 -1
- package/web-app/dist/assets/{TemplatesPage-BWHWVk0L.js → TemplatesPage-B6iFgH6t.js} +1 -1
- package/web-app/dist/assets/{TerminalOutput-Cv3N3Szf.js → TerminalOutput-B3yzZe-h.js} +1 -1
- package/web-app/dist/assets/{activity-dEhz-bXR.js → activity-CNfAjtRv.js} +1 -1
- package/web-app/dist/assets/{bell-B3XUMq1t.js → bell-CMETsHPH.js} +1 -1
- package/web-app/dist/assets/{bot-X-ssNlwR.js → bot-C9kXvk1i.js} +1 -1
- package/web-app/dist/assets/{check-C_9Nx7kb.js → check-BRK-zLB5.js} +1 -1
- package/web-app/dist/assets/{chevron-left-tvNswo3A.js → chevron-left-CxI5uD4g.js} +1 -1
- package/web-app/dist/assets/{circle-alert-CSB88nEs.js → circle-alert-CVFRPWpv.js} +1 -1
- package/web-app/dist/assets/{clock-C8p2e4NI.js → clock-CLYV8a_x.js} +1 -1
- package/web-app/dist/assets/{cloud-CKp2ZvhG.js → cloud-CiISiIOa.js} +1 -1
- package/web-app/dist/assets/{code-xml-dY70LCHD.js → code-xml-DHsgqwV-.js} +1 -1
- package/web-app/dist/assets/{database-DObn5fmn.js → database-DbvUqtz3.js} +1 -1
- package/web-app/dist/assets/{dollar-sign-DSu6n3K3.js → dollar-sign-Ct0lRPHw.js} +1 -1
- package/web-app/dist/assets/{file-code-corner-DpCnS73z.js → file-code-corner-D1sjFEh7.js} +1 -1
- package/web-app/dist/assets/{file-plus-D3IPKCf1.js → file-plus-DnmX18Fi.js} +1 -1
- package/web-app/dist/assets/{globe-C9QXkgH_.js → globe-bSpDNgoA.js} +1 -1
- package/web-app/dist/assets/{hammer-D_FtWe1y.js → hammer-Bj41Kvlq.js} +1 -1
- package/web-app/dist/assets/{index-CI54rara.css → index-BfQ0f3-S.css} +1 -1
- package/web-app/dist/assets/{index-Cz7q1bvC.js → index-CxajNJVu.js} +3 -3
- package/web-app/dist/assets/{layers-DsW7jnJX.js → layers-BNtBwYER.js} +1 -1
- package/web-app/dist/assets/{loader-circle-B3HspjKR.js → loader-circle-YY_VZofG.js} +1 -1
- package/web-app/dist/assets/{lock-DSI29pct.js → lock-rpjEPVoC.js} +1 -1
- package/web-app/dist/assets/{package-CLNxtA2x.js → package-desXU6XA.js} +1 -1
- package/web-app/dist/assets/{plus-DyI4WC4_.js → plus-7AoOU-I9.js} +1 -1
- package/web-app/dist/assets/{refresh-cw-D2dv0xA0.js → refresh-cw-oNj-Xn4B.js} +1 -1
- package/web-app/dist/assets/{rotate-ccw-CBvihA-a.js → rotate-ccw-DeiFjfVO.js} +1 -1
- package/web-app/dist/assets/{scroll-text-DvoOvAl_.js → scroll-text-Q9AzWiNV.js} +1 -1
- package/web-app/dist/assets/{server-DenWvSUt.js → server-DKgVwfek.js} +1 -1
- package/web-app/dist/assets/{shield-alert-40cX_FvG.js → shield-alert-G6x-bS-I.js} +1 -1
- package/web-app/dist/assets/{thumbs-up-BrjZ6QuV.js → thumbs-up-Qhk0yvw0.js} +1 -1
- package/web-app/dist/assets/{trash-2-C6evwkEH.js → trash-2-D23gvznl.js} +1 -1
- package/web-app/dist/assets/{trending-down-CfbZis3O.js → trending-down-CSQClPrr.js} +1 -1
- package/web-app/dist/assets/{trending-up-DWuEK3WC.js → trending-up-sjMSd1wc.js} +1 -1
- package/web-app/dist/assets/{upload-B9DFBcPG.js → upload-Dchovhld.js} +1 -1
- package/web-app/dist/assets/{usePolling-BryVC-T1.js → usePolling-DwLceXwF.js} +1 -1
- package/web-app/dist/assets/{user-DMRXwZiw.js → user-BqZM8CmD.js} +1 -1
- package/web-app/dist/index.html +2 -2
- package/web-app/server.py +52 -17
- package/web-app/dist/assets/CockpitPage-DVMk2RUK.js +0 -47
- package/web-app/dist/assets/ComparePage-NMLyE1xL.js +0 -1
- package/web-app/dist/assets/EvidenceReceiptPanel-D2LNKqUx.js +0 -1
- package/web-app/dist/assets/GitHubPRsPanel-BSlmoVTS.js +0 -17
package/autonomy/loki
CHANGED
|
@@ -36974,18 +36974,28 @@ print(json.dumps(json.load(open(os.environ['LOKI_PROOF_JSON'])), indent=2))
|
|
|
36974
36974
|
echo -e "${YELLOW}NOT CHECKED${NC}: python3 is not on PATH, so the verifier could not run (exit 2)." >&2
|
|
36975
36975
|
exit 2
|
|
36976
36976
|
fi
|
|
36977
|
-
local _pv_rc=0
|
|
36977
|
+
local _pv_rc=0 _pv_out="" _pv_base_rc=0
|
|
36978
|
+
# Captured, not printed directly, so that --jwks (below) can patch
|
|
36979
|
+
# it: BACKLOG 49 -- when --jwks later downgrades _pv_rc to 1
|
|
36980
|
+
# (ABSENT) or 2 (NOT CHECKED), this output's own "ok: true"/
|
|
36981
|
+
# VERIFIED header from the base hash/drift check must not still be
|
|
36982
|
+
# the last word on stdout. Unflagged (no --jwks), this is printed
|
|
36983
|
+
# byte-for-byte as the base verifier produced it, same as the Bun
|
|
36984
|
+
# route (proof.ts verifyProof) -- ok already agrees with the exit
|
|
36985
|
+
# code there, so there is nothing to patch.
|
|
36978
36986
|
if [ "$_pv_human" -eq 1 ]; then
|
|
36979
|
-
python3 -E "$verifier" --human "$pj" "${TARGET_DIR:-.}" || _pv_rc=$?
|
|
36987
|
+
_pv_out="$(python3 -E "$verifier" --human "$pj" "${TARGET_DIR:-.}")" || _pv_rc=$?
|
|
36980
36988
|
else
|
|
36981
|
-
python3 -E "$verifier" "$pj" "${TARGET_DIR:-.}" || _pv_rc=$?
|
|
36989
|
+
_pv_out="$(python3 -E "$verifier" "$pj" "${TARGET_DIR:-.}")" || _pv_rc=$?
|
|
36982
36990
|
fi
|
|
36991
|
+
_pv_base_rc="$_pv_rc"
|
|
36983
36992
|
|
|
36984
36993
|
# The attestation check runs AFTER, and can only make the verdict
|
|
36985
36994
|
# worse, never better. A valid attestation does not excuse a failed
|
|
36986
36995
|
# integrity hash: the signature proves who produced the bytes, not
|
|
36987
36996
|
# that the bytes are internally consistent. Folding the two together
|
|
36988
36997
|
# would let a signed-but-tampered receipt exit 0.
|
|
36998
|
+
local _pv_attestation_field="n/a"
|
|
36989
36999
|
if [ -n "$_pv_jwks" ]; then
|
|
36990
37000
|
local _pv_att
|
|
36991
37001
|
_pv_att="$(loki_proof_attestation_check "$pj" "$_pv_jwks")"
|
|
@@ -36994,12 +37004,14 @@ print(json.dumps(json.load(open(os.environ['LOKI_PROOF_JSON'])), indent=2))
|
|
|
36994
37004
|
echo "attestation: VERIFIED against ${_pv_jwks}" >&2
|
|
36995
37005
|
echo " Proven: these bytes were signed by the holder of a key in that set." >&2
|
|
36996
37006
|
echo " NOT proven: that the code is correct. A receipt records which checks ran." >&2
|
|
37007
|
+
_pv_attestation_field="VERIFIED"
|
|
36997
37008
|
;;
|
|
36998
37009
|
bad)
|
|
36999
37010
|
echo -e "${RED}attestation: FAILED -- the token does not cover these bytes.${NC}" >&2
|
|
37000
37011
|
echo " Either the receipt was altered after signing, or the attestation" >&2
|
|
37001
37012
|
echo " belongs to a different run. Do not trust this receipt." >&2
|
|
37002
37013
|
_pv_rc=1
|
|
37014
|
+
_pv_attestation_field="FAILED"
|
|
37003
37015
|
;;
|
|
37004
37016
|
none)
|
|
37005
37017
|
# Exit 1: the caller supplied a key set and asked who
|
|
@@ -37011,6 +37023,7 @@ print(json.dumps(json.load(open(os.environ['LOKI_PROOF_JSON'])), indent=2))
|
|
|
37011
37023
|
echo " gpg-signed; this says only that it has no JWKS attestation." >&2
|
|
37012
37024
|
echo " Not verified: a key set was supplied, but the receipt is unsigned (exit 1)." >&2
|
|
37013
37025
|
_pv_rc=1
|
|
37026
|
+
_pv_attestation_field="ABSENT"
|
|
37014
37027
|
;;
|
|
37015
37028
|
*)
|
|
37016
37029
|
# Unreachable key set, unreadable file, missing python
|
|
@@ -37021,9 +37034,126 @@ print(json.dumps(json.load(open(os.environ['LOKI_PROOF_JSON'])), indent=2))
|
|
|
37021
37034
|
echo -e "${YELLOW}attestation: NOT CHECKED -- could not check against ${_pv_jwks} (key set unreadable, or verifier dependency missing).${NC}" >&2
|
|
37022
37035
|
echo " This is not a failure of the receipt. Nothing was proven either way (exit 2)." >&2
|
|
37023
37036
|
if [ "$_pv_rc" -eq 0 ]; then _pv_rc=2; fi
|
|
37037
|
+
_pv_attestation_field="NOT CHECKED"
|
|
37024
37038
|
;;
|
|
37025
37039
|
esac
|
|
37026
37040
|
fi
|
|
37041
|
+
# Only patch when --jwks put a THIRD input (the attestation) into
|
|
37042
|
+
# the verdict. With no --jwks, ok/the header already agree with the
|
|
37043
|
+
# exit code (both come straight from the base verifier), and
|
|
37044
|
+
# output is printed byte-for-byte: unflagged output is identical
|
|
37045
|
+
# to before this change, on both the bash and Bun routes.
|
|
37046
|
+
if [ -n "$_pv_jwks" ]; then
|
|
37047
|
+
# Rewrite the base verifier's output so ok/verdict (JSON) or
|
|
37048
|
+
# the header line (--human) always agree with $_pv_rc, the
|
|
37049
|
+
# exit code this command actually returns. verdict reads
|
|
37050
|
+
# doc["hash_ok"] (the parsed JSON) AND the attestation field
|
|
37051
|
+
# together: hash_ok False is TAMPERED, and a bad signature
|
|
37052
|
+
# against otherwise-good bytes is ALSO TAMPERED (the token
|
|
37053
|
+
# proves the bytes came from an untrusted source, which is the
|
|
37054
|
+
# same class of finding as a rewritten hash); diff_drift True
|
|
37055
|
+
# (or unverifiable, e.g. wrong TARGET_DIR) is drift, NOT
|
|
37056
|
+
# tampering -- loki_remote_verify_receipt draws the same line
|
|
37057
|
+
# -- so drift with an otherwise-valid or absent attestation
|
|
37058
|
+
# must stay FAILED, never TAMPERED.
|
|
37059
|
+
# -E plus the explicit sys.path strip BEFORE importing
|
|
37060
|
+
# json/os: PYTHONPATH and a committed sitecustomize.py must
|
|
37061
|
+
# not run here, same guard as the attestation check above
|
|
37062
|
+
# (loki_proof_attestation_check). The strip runs first so a
|
|
37063
|
+
# shadow json.py planted in the invocation cwd cannot
|
|
37064
|
+
# intercept this import either.
|
|
37065
|
+
_V_BASE_RC="$_pv_base_rc" _V_RC="$_pv_rc" _V_ATTESTATION="$_pv_attestation_field" _V_HUMAN="$_pv_human" python3 -E -c '
|
|
37066
|
+
import sys; sys.path[:] = [p for p in sys.path if p not in ("", ".")]
|
|
37067
|
+
import json, os
|
|
37068
|
+
|
|
37069
|
+
raw = sys.stdin.read()
|
|
37070
|
+
base_rc = int(os.environ["_V_BASE_RC"])
|
|
37071
|
+
rc = int(os.environ["_V_RC"])
|
|
37072
|
+
attestation = os.environ["_V_ATTESTATION"]
|
|
37073
|
+
human = os.environ["_V_HUMAN"] == "1"
|
|
37074
|
+
|
|
37075
|
+
# --human never gets the JSON report (render_reasons only prints a header
|
|
37076
|
+
# plus prose), so doc stays None there and hash_ok cannot be consulted; the
|
|
37077
|
+
# JSON branch below parses raw first so it CAN consult doc.get("hash_ok").
|
|
37078
|
+
doc = None
|
|
37079
|
+
if not human:
|
|
37080
|
+
try:
|
|
37081
|
+
doc = json.loads(raw)
|
|
37082
|
+
except ValueError:
|
|
37083
|
+
doc = None
|
|
37084
|
+
|
|
37085
|
+
if rc == 0:
|
|
37086
|
+
verdict = "VERIFIED"
|
|
37087
|
+
elif rc == 2:
|
|
37088
|
+
# Exit 2 is always "could not check" (missing verifier, malformed
|
|
37089
|
+
# proof.json, or --jwks NOT CHECKED) -- never an accusation.
|
|
37090
|
+
verdict = "NOT CHECKED"
|
|
37091
|
+
elif base_rc != 0:
|
|
37092
|
+
# The base check itself found something: a real tamper/drift finding, or
|
|
37093
|
+
# it could not run at all (malformed proof.json, doc is None). A definite
|
|
37094
|
+
# hash mismatch is TAMPERED. So is a bad signature against otherwise-good
|
|
37095
|
+
# bytes (attestation FAILED): the token proves these bytes were not
|
|
37096
|
+
# produced by a trusted signer, which is the same accusation a rewritten
|
|
37097
|
+
# hash makes, just caught by a different mechanism -- a drifted tree
|
|
37098
|
+
# checked against the WRONG key still means "do not trust this receipt,"
|
|
37099
|
+
# not merely "could not confirm it." Anything else here (drift, drift-
|
|
37100
|
+
# unverifiable, cost/headline incoherence, or a base verifier error) is
|
|
37101
|
+
# FAILED, the same word "loki proof verify --human" already uses for a
|
|
37102
|
+
# non-tamper finding, rather than an accusation the data does not
|
|
37103
|
+
# support. --human never sees doc (it is prose, not JSON), so it relies
|
|
37104
|
+
# on the attestation field alone here; the JSON branch below can also
|
|
37105
|
+
# consult hash_ok.
|
|
37106
|
+
verdict = "TAMPERED" if (attestation == "FAILED" or (doc is not None and doc.get("hash_ok") is False)) else "FAILED"
|
|
37107
|
+
else:
|
|
37108
|
+
# Base check passed (rc would have been 0 otherwise); --jwks is what
|
|
37109
|
+
# pushed the final rc to 1. Only two attestation outcomes do that: a bad
|
|
37110
|
+
# signature (a tamper finding, once the base bytes are known good) or no
|
|
37111
|
+
# signature at all (ABSENT, a fact about the receipt, not an accusation).
|
|
37112
|
+
verdict = "TAMPERED" if attestation == "FAILED" else "ABSENT"
|
|
37113
|
+
|
|
37114
|
+
if human:
|
|
37115
|
+
# The --human vocabulary (render_reasons) is only three words: VERIFIED /
|
|
37116
|
+
# COULD NOT CHECK / FAILED. verdict (five words, shared with the JSON
|
|
37117
|
+
# branch) maps onto it rather than being printed raw, so a TAMPERED or
|
|
37118
|
+
# ABSENT finding still reads as the header word this flag readers
|
|
37119
|
+
# already parse for a failure. --human has no fifth word of its own for
|
|
37120
|
+
# TAMPERED; a real integrity/attestation failure and a non-tamper finding
|
|
37121
|
+
# both print "FAILED" to a human reader, same as before this fix -- only
|
|
37122
|
+
# the JSON verdict field distinguishes the two.
|
|
37123
|
+
header = {
|
|
37124
|
+
"VERIFIED": "VERIFIED",
|
|
37125
|
+
"NOT CHECKED": "COULD NOT CHECK",
|
|
37126
|
+
}.get(verdict, "FAILED")
|
|
37127
|
+
# Only the header line can disagree with rc (it reflects the base check
|
|
37128
|
+
# alone, computed before --jwks); replace just that line so the
|
|
37129
|
+
# per-reason " - ..." detail from the base verifier survives untouched.
|
|
37130
|
+
lines = raw.split("\n")
|
|
37131
|
+
if lines and lines[0].strip() in ("VERIFIED", "COULD NOT CHECK", "FAILED"):
|
|
37132
|
+
lines[0] = header
|
|
37133
|
+
sys.stdout.write("\n".join(lines))
|
|
37134
|
+
sys.exit(0)
|
|
37135
|
+
|
|
37136
|
+
if doc is None:
|
|
37137
|
+
# Base verifier printed something unparseable (should not happen; the
|
|
37138
|
+
# base verifier always emits JSON, even on its own internal error). Pass
|
|
37139
|
+
# it through unchanged rather than fabricate a report over data we cannot
|
|
37140
|
+
# read.
|
|
37141
|
+
sys.stdout.write(raw)
|
|
37142
|
+
sys.exit(0)
|
|
37143
|
+
|
|
37144
|
+
doc["verdict"] = verdict
|
|
37145
|
+
doc["attestation"] = attestation
|
|
37146
|
+
# ok is superseded by verdict, which cannot silently drift from the exit
|
|
37147
|
+
# code the way a second boolean could. Kept for existing readers, but forced
|
|
37148
|
+
# to agree with rc instead of repeating the base verifier own possibly-
|
|
37149
|
+
# passing opinion, so a stdout-only consumer reading "ok" is never told the
|
|
37150
|
+
# opposite of what this process just exited with.
|
|
37151
|
+
doc["ok"] = (rc == 0)
|
|
37152
|
+
print(json.dumps(doc, indent=2))
|
|
37153
|
+
' <<<"$_pv_out" || printf '%s\n' "$_pv_out"
|
|
37154
|
+
else
|
|
37155
|
+
printf '%s\n' "$_pv_out"
|
|
37156
|
+
fi
|
|
37027
37157
|
exit "$_pv_rc"
|
|
37028
37158
|
;;
|
|
37029
37159
|
open)
|