loki-mode 11.89.0 → 11.90.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/backlog.py +9 -0
- package/autonomy/loki +71 -1
- package/dashboard/__init__.py +1 -1
- package/docs/CLI-REFERENCE.md +1 -1
- package/docs/INSTALLATION.md +1 -1
- package/docs/v11/VERIFY-PR-SANDBOX.md +2 -0
- package/loki-ts/dist/loki.js +1312 -1309
- package/mcp/__init__.py +1 -1
- package/package.json +2 -2
- package/packages/control-plane/dist/server.js +1409 -1151
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/web-app/dist/assets/{AdminPage-BQLmlBoU.js → AdminPage-CZL0cONl.js} +1 -1
- package/web-app/dist/assets/{Avatar-sPMrfkwo.js → Avatar-tJZxSP21.js} +1 -1
- package/web-app/dist/assets/{Badge-D6bf5ZNR.js → Badge-B-uFJM_y.js} +1 -1
- package/web-app/dist/assets/{Button-BKMmzs4p.js → Button-DfKU7ctr.js} +1 -1
- package/web-app/dist/assets/{CockpitPage-Cobt_89E.js → CockpitPage-CRNp09jN.js} +1 -1
- package/web-app/dist/assets/{ComparePage-D3_PQ05B.js → ComparePage-Cdvjcs57.js} +1 -1
- package/web-app/dist/assets/{ErrorBoundary-YMrMfXT1.js → ErrorBoundary-C_benNK3.js} +1 -1
- package/web-app/dist/assets/{EvidenceReceiptPanel-wFjp7S3Y.js → EvidenceReceiptPanel-Ch_6YkUO.js} +1 -1
- package/web-app/dist/assets/{GitHubIssuesPanel-DpkjZRyt.js → GitHubIssuesPanel-C_a7mAlw.js} +1 -1
- package/web-app/dist/assets/{GitHubPRsPanel-AVnL3HWL.js → GitHubPRsPanel-xMr7IKsr.js} +1 -1
- package/web-app/dist/assets/{HomePage-B0MtpdPg.js → HomePage-BVe6s1kz.js} +2 -2
- package/web-app/dist/assets/{LoginPage-CC80bz-e.js → LoginPage-DKlLaNw0.js} +1 -1
- package/web-app/dist/assets/{MagicPage-DVV83HJy.js → MagicPage-StmxQunX.js} +1 -1
- package/web-app/dist/assets/{MetricsPage-C5BkFI0J.js → MetricsPage-C7e2CioT.js} +1 -1
- package/web-app/dist/assets/{NotFoundPage-s1rzn42S.js → NotFoundPage-B2IopV0V.js} +1 -1
- package/web-app/dist/assets/{ProjectPage-B0agoWbD.js → ProjectPage-CXs8d6Cx.js} +3 -3
- package/web-app/dist/assets/{ProjectsPage-BOm_XFI3.js → ProjectsPage-BfgMJYYj.js} +1 -1
- package/web-app/dist/assets/{SettingsPage-DQz1M_vu.js → SettingsPage-CZ8lwCF2.js} +1 -1
- package/web-app/dist/assets/{ShowcasePage-B2TVXqEE.js → ShowcasePage-iNCfKZj0.js} +1 -1
- package/web-app/dist/assets/{SystemSettingsPage-CrfoTgPb.js → SystemSettingsPage-FMV2pNNz.js} +1 -1
- package/web-app/dist/assets/{TeamsPage-BLGlLcfL.js → TeamsPage-D_SzTjuD.js} +1 -1
- package/web-app/dist/assets/{TemplatesPage-iipnnIUw.js → TemplatesPage-BMF_6X7R.js} +1 -1
- package/web-app/dist/assets/{TerminalOutput-B5pOWLP1.js → TerminalOutput-ClZtwhW8.js} +1 -1
- package/web-app/dist/assets/{activity-DNQZDHv_.js → activity-DSOGDSlj.js} +1 -1
- package/web-app/dist/assets/{bell-BcOHxEZp.js → bell-BQaMS_Ge.js} +1 -1
- package/web-app/dist/assets/{bot-DJHk8DIS.js → bot-Iw0qLbSN.js} +1 -1
- package/web-app/dist/assets/{check-DLcpqjjW.js → check-BNNpt5tE.js} +1 -1
- package/web-app/dist/assets/{chevron-left-BBmSCXx7.js → chevron-left-DDFdacve.js} +1 -1
- package/web-app/dist/assets/{circle-alert-B2CgD1z3.js → circle-alert-CiRTbi7c.js} +1 -1
- package/web-app/dist/assets/{clock-CLTNw-dw.js → clock-hudCD7-Z.js} +1 -1
- package/web-app/dist/assets/{cloud-BMJEQNqp.js → cloud-Brn55LA3.js} +1 -1
- package/web-app/dist/assets/{code-xml-BmFkHUyF.js → code-xml-kiS4rISP.js} +1 -1
- package/web-app/dist/assets/{database-Bq9o-0ff.js → database-BD1l1Tuw.js} +1 -1
- package/web-app/dist/assets/{dollar-sign-CPvl4BSY.js → dollar-sign-DT5e3PIo.js} +1 -1
- package/web-app/dist/assets/{file-code-corner-Ok780J5c.js → file-code-corner-DmixJzQ5.js} +1 -1
- package/web-app/dist/assets/{file-plus-C-mvuzqz.js → file-plus-CeQieVbR.js} +1 -1
- package/web-app/dist/assets/{globe-7nchOhax.js → globe-BayFHork.js} +1 -1
- package/web-app/dist/assets/{hammer--C-eV19O.js → hammer-BzJ_7lDH.js} +1 -1
- package/web-app/dist/assets/{index-BY0d2rJT.js → index-DgDlNUmy.js} +3 -3
- package/web-app/dist/assets/{layers-B3T1id14.js → layers-CfWES4J2.js} +1 -1
- package/web-app/dist/assets/{loader-circle-CtsL9AIK.js → loader-circle-CH0UbcAO.js} +1 -1
- package/web-app/dist/assets/{lock-C5gtyC-I.js → lock-BuKglb_x.js} +1 -1
- package/web-app/dist/assets/{package-BWa9VJ_J.js → package-BkpU_Qb_.js} +1 -1
- package/web-app/dist/assets/{plus-CbrYo3zc.js → plus-BFMNyc0G.js} +1 -1
- package/web-app/dist/assets/{refresh-cw-DpSr1VHS.js → refresh-cw-DQnQVKNC.js} +1 -1
- package/web-app/dist/assets/{rotate-ccw-CGfdW9Iq.js → rotate-ccw-B_M9AdjB.js} +1 -1
- package/web-app/dist/assets/{scroll-text-DJQaMueH.js → scroll-text-1P39rc_L.js} +1 -1
- package/web-app/dist/assets/{server-gW2YYTQK.js → server-BjGwVEsb.js} +1 -1
- package/web-app/dist/assets/{shield-alert-Q8pgbz-s.js → shield-alert-CKcYjHu8.js} +1 -1
- package/web-app/dist/assets/{thumbs-up-Du9_EC4t.js → thumbs-up-BC_5mpCw.js} +1 -1
- package/web-app/dist/assets/{trash-2-D_P45JH4.js → trash-2-CjtQl9fg.js} +1 -1
- package/web-app/dist/assets/{trending-down-B4tyujmD.js → trending-down-D9MnFNOD.js} +1 -1
- package/web-app/dist/assets/{trending-up-CkSU2NRR.js → trending-up-DrHz29bk.js} +1 -1
- package/web-app/dist/assets/{upload-Mh6nzuC2.js → upload-D7jmahPb.js} +1 -1
- package/web-app/dist/assets/{usePolling-BWRlQ0Ir.js → usePolling-C-zxuzqz.js} +1 -1
- package/web-app/dist/assets/{user-BF6I3BoG.js → user-DE2Mkf9B.js} +1 -1
- package/web-app/dist/index.html +1 -1
package/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: loki-mode
|
|
|
3
3
|
description: Runs an autonomous software factory that knows what it is supposed to deliver and proves it did, with a signed receipt. Use when the user says Loki Mode or asks to build, fix or verify software autonomously.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Loki Mode v11.
|
|
6
|
+
# Loki Mode v11.90.0
|
|
7
7
|
|
|
8
8
|
**Current entry points (Loki 10 engine):** `loki "<task>"`, `loki owner/repo#N` and `loki quick "<task>"` run the Loki 10 engine and end with a signed receipt (`loki verify`). `loki backlog owner/repo --all` runs many issues in parallel. Guide: `docs/v10/GUIDE.md`. The skill instructions below, and `loki start`, describe the previous bash loop. PRD-file starts (`loki start ./prd.md`) and the opencode provider still run on it until FC38-SWEEP ports them; the legacy-engine command and the LOKI_ENGINE switch remain removed. Prefer `loki owner/repo#N` for issues.
|
|
9
9
|
|
|
@@ -475,4 +475,4 @@ Implemented, planned and deprecated items, with the version each landed in: `ski
|
|
|
475
475
|
|
|
476
476
|
---
|
|
477
477
|
|
|
478
|
-
**v11.
|
|
478
|
+
**v11.90.0 | [Autonomi](https://www.autonomi.dev/) flagship product | core skill**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
11.
|
|
1
|
+
11.90.0
|
package/autonomy/lib/backlog.py
CHANGED
|
@@ -378,6 +378,15 @@ def main(argv):
|
|
|
378
378
|
tmp = dst + ".tmp%d" % os.getpid()
|
|
379
379
|
shutil.copyfile(src, tmp)
|
|
380
380
|
os.replace(tmp, dst)
|
|
381
|
+
# The sealed Wall copies travel with the receipt: integrate reruns them on the merged tree after the worktree is gone.
|
|
382
|
+
wsrc, wdst = os.path.join(src_dir, "wall"), os.path.join(dst_dir, "wall")
|
|
383
|
+
if os.path.isdir(wsrc) and not os.path.islink(wsrc) and not os.path.islink(wdst):
|
|
384
|
+
shutil.rmtree(wdst, ignore_errors=True)
|
|
385
|
+
os.makedirs(wdst, mode=0o700, exist_ok=True)
|
|
386
|
+
for name in os.listdir(wsrc):
|
|
387
|
+
f = os.path.join(wsrc, name)
|
|
388
|
+
if os.path.isfile(f) and not os.path.islink(f):
|
|
389
|
+
shutil.copyfile(f, os.path.join(wdst, name))
|
|
381
390
|
except OSError:
|
|
382
391
|
pass
|
|
383
392
|
|
package/autonomy/loki
CHANGED
|
@@ -28170,13 +28170,75 @@ _pr_record_merge() {
|
|
|
28170
28170
|
return 0
|
|
28171
28171
|
}
|
|
28172
28172
|
|
|
28173
|
+
# Owner opt-in earned merge (LOKI_EARNED_MERGE=1, off by default). Every path
|
|
28174
|
+
# the PR changes (the new name and, for a rename, the previous name, listed by
|
|
28175
|
+
# paginated REST and required to match the PR's changedFiles count) must have a
|
|
28176
|
+
# Seal record from `loki trust --json` (path_seals) with at least
|
|
28177
|
+
# LOKI_EARNED_MERGE_MIN_VERIFIED (default 20, floor 1) VERIFIED receipts and
|
|
28178
|
+
# exactly 0 reverts in git history. A revert count of null (history
|
|
28179
|
+
# unreadable), a missing record, an unreadable trust output or an unreadable or
|
|
28180
|
+
# truncated file list or an unreadable diff all refuse, as does any PR whose
|
|
28181
|
+
# diff touches a symlink (120000) or submodule (160000) mode. Protected paths (.github/, .loki/, .env*,
|
|
28182
|
+
# .envrc, CODEOWNERS, plus the space-separated globs in
|
|
28183
|
+
# LOKI_EARNED_MERGE_PROTECTED), matched case-insensitively, always stay
|
|
28184
|
+
# PR-only. The reason for a refusal goes to stdout; the return code is 1.
|
|
28185
|
+
_pr_earned_merge_check() {
|
|
28186
|
+
local pr="$1" min="${LOKI_EARNED_MERGE_MIN_VERIFIED:-20}" meta="" num="" want="" lines="" seals=""
|
|
28187
|
+
local kind p lp g row v r got=0 globs=() diff="" bad_mode=""
|
|
28188
|
+
case "$min" in ''|*[!0-9]*) min=20 ;; esac
|
|
28189
|
+
[ "$min" -ge 1 ] || min=1
|
|
28190
|
+
command -v jq >/dev/null 2>&1 || { echo "jq is required to read the Seal record"; return 1; }
|
|
28191
|
+
meta="$(gh pr view "$pr" --json number,changedFiles -q '"\(.number) \(.changedFiles)"' 2>/dev/null)" || meta=""
|
|
28192
|
+
num="${meta%% *}"; want="${meta#* }"
|
|
28193
|
+
case "$num$want" in ''|*[!0-9]*) echo "the PR's changed files are unreadable"; return 1 ;; esac
|
|
28194
|
+
lines="$(gh api --paginate "repos/{owner}/{repo}/pulls/${num}/files" -q '.[] | ("F\t" + .filename), (select(.previous_filename != null) | "P\t" + .previous_filename)' 2>/dev/null)" || lines=""
|
|
28195
|
+
[ -n "$lines" ] || { echo "the PR's changed files are unreadable"; return 1; }
|
|
28196
|
+
seals="$("$_LOKI_SCRIPT_DIR/../bin/loki" trust --json 2>/dev/null)" || seals=""
|
|
28197
|
+
printf '%s' "$seals" | jq -e '.path_seals | type == "array"' >/dev/null 2>&1 || { echo "the Seal record is unreadable"; return 1; }
|
|
28198
|
+
# read -a splits on whitespace without expanding globs against the cwd.
|
|
28199
|
+
read -r -a globs <<EOF_GLOBS
|
|
28200
|
+
$(printf '%s' "${LOKI_EARNED_MERGE_PROTECTED:-}" | tr '[:upper:]' '[:lower:]')
|
|
28201
|
+
EOF_GLOBS
|
|
28202
|
+
while IFS="$(printf '\t')" read -r kind p; do
|
|
28203
|
+
[ -n "$p" ] || continue
|
|
28204
|
+
[ "$kind" = "F" ] && got=$((got + 1))
|
|
28205
|
+
lp="$(printf '%s' "$p" | tr '[:upper:]' '[:lower:]')"
|
|
28206
|
+
case "$lp" in .github/*|.loki/*|.env|.env.*|*/.env|*/.env.*|.envrc|*/.envrc|codeowners|docs/codeowners)
|
|
28207
|
+
echo "$p is a protected path"; return 1 ;;
|
|
28208
|
+
esac
|
|
28209
|
+
for g in ${globs[@]+"${globs[@]}"}; do
|
|
28210
|
+
# shellcheck disable=SC2254
|
|
28211
|
+
case "$lp" in $g) echo "$p is a protected path"; return 1 ;; esac
|
|
28212
|
+
done
|
|
28213
|
+
row="$(printf '%s' "$seals" | jq -r --arg p "$p" '[.path_seals[] | select(.path == $p)] | if length == 0 then "none" else "\(.[0].verified) \(.[0].reverts)" end')" || row="none"
|
|
28214
|
+
[ "$row" != "none" ] || { echo "$p has no Seal record"; return 1; }
|
|
28215
|
+
v="${row%% *}"; r="${row#* }"
|
|
28216
|
+
case "$r" in
|
|
28217
|
+
0) ;;
|
|
28218
|
+
null) echo "$p revert status is unknown"; return 1 ;;
|
|
28219
|
+
*) echo "$p has $r recorded revert(s)"; return 1 ;;
|
|
28220
|
+
esac
|
|
28221
|
+
[ "$v" -ge "$min" ] 2>/dev/null || { echo "$p has $v VERIFIED receipts, need $min"; return 1; }
|
|
28222
|
+
done <<EOF_FILES
|
|
28223
|
+
$lines
|
|
28224
|
+
EOF_FILES
|
|
28225
|
+
[ "$got" = "$want" ] || { echo "the PR lists $want changed files but $got were readable"; return 1; }
|
|
28226
|
+
# A symlink (120000) or submodule (160000) can point an earned path anywhere:
|
|
28227
|
+
# refuse any PR whose diff adds, removes, changes or re-modes one.
|
|
28228
|
+
diff="$(gh pr diff "$pr" 2>/dev/null)" || diff=""
|
|
28229
|
+
[ -n "$diff" ] || { echo "the PR's file modes are unreadable"; return 1; }
|
|
28230
|
+
bad_mode="$(printf '%s\n' "$diff" | awk '/^diff --git /{h=$0} /^(new file mode|deleted file mode|old mode|new mode) (120000|160000)$/{print h; exit} /^index [0-9a-f.]+ (120000|160000)$/{print h; exit}')"
|
|
28231
|
+
[ -z "$bad_mode" ] || { echo "${bad_mode#diff --git } involves a symlink or submodule"; return 1; }
|
|
28232
|
+
return 0
|
|
28233
|
+
}
|
|
28234
|
+
|
|
28173
28235
|
# Shared merge gate. One PR (number or branch) merges only when it is not a
|
|
28174
28236
|
# draft, `gh pr checks` exits 0 after polling pending (rc=8), and, with
|
|
28175
28237
|
# --require-verified, every clean proof recorded for the PR's head commit
|
|
28176
28238
|
# (facts.git.head_sha == headRefOid, dirty-tree proofs ignored) says VERIFIED; a stale or missing proof
|
|
28177
28239
|
# refuses ("gate: head"). The merge passes --match-head-commit so a push after
|
|
28178
28240
|
# the gate cannot land unjudged. On refusal it prints the exact blocking gate
|
|
28179
|
-
# ("gate: draft|head|verdict|checks") and leaves the PR open.
|
|
28241
|
+
# ("gate: draft|head|verdict|trust|checks") and leaves the PR open.
|
|
28180
28242
|
# Usage: _merge_pr_gated <pr> [--require-verified] [--delete-branch]
|
|
28181
28243
|
_merge_pr_gated() {
|
|
28182
28244
|
local pr="$1" need_verified=false margs=(--squash) rc d
|
|
@@ -28252,6 +28314,14 @@ _merge_pr_gated() {
|
|
|
28252
28314
|
return 1
|
|
28253
28315
|
fi
|
|
28254
28316
|
fi
|
|
28317
|
+
if [ "${LOKI_EARNED_MERGE:-0}" = "1" ]; then
|
|
28318
|
+
local trust_why=""
|
|
28319
|
+
trust_why="$(_pr_earned_merge_check "$pr")" || {
|
|
28320
|
+
echo "$pr: not merged, gate: trust ($trust_why); PR left open" >&2
|
|
28321
|
+
_pr_record_merge "$pr" "blocked:trust" "trust"
|
|
28322
|
+
return 1
|
|
28323
|
+
}
|
|
28324
|
+
fi
|
|
28255
28325
|
rc=0; _pr_checks_wait "$pr" || rc=$?
|
|
28256
28326
|
if [ "$rc" != "0" ]; then
|
|
28257
28327
|
echo "$pr: not merged, gate: checks (gh pr checks rc=$rc); PR left open" >&2
|
package/dashboard/__init__.py
CHANGED
package/docs/CLI-REFERENCE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# CLI reference
|
|
2
2
|
|
|
3
|
-
Generated from `loki-ts/src/cli/registry.ts` by `scripts/generate-stale-zero.sh` for v11.
|
|
3
|
+
Generated from `loki-ts/src/cli/registry.ts` by `scripts/generate-stale-zero.sh` for v11.90.0. Do not edit by hand.
|
|
4
4
|
Hidden and legacy-only commands are omitted; see `docs/CLI-INVENTORY.md` for the full inventory.
|
|
5
5
|
|
|
6
6
|
| Command | Description |
|
package/docs/INSTALLATION.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Loki Mode, by [Autonomi](https://www.autonomi.dev/), turns a spec or an issue into a verified pull request with a receipt you can check. This page covers installing it, a first run, and the options around it.
|
|
4
4
|
|
|
5
|
-
**Version:** v11.
|
|
5
|
+
**Version:** v11.90.0
|
|
6
6
|
|
|
7
7
|
**Engine note:** `loki start` is the primary command. `loki start`, `loki "<task>"`, `loki owner/repo#N` and `loki quick` all run the Loki 10 engine, whatever the flag order or input form (PRD file, issue ref, task or one-word brief). The previous loop runs only on `--engine legacy`, `LOKI_ENGINE=legacy`, or for one call when a flag Loki 10 cannot honor is present. See the [user guide](v10/GUIDE.md) and the [5-minute quickstart](QUICKSTART.md).
|
|
8
8
|
|
|
@@ -25,6 +25,7 @@ verify-pr-sandbox.sh --repo DIR --out DIR --cmd 'SHELL CMD' --image IMG [--timeo
|
|
|
25
25
|
| Env scrub | `docker run` inherits no host env; only PATH, HOME=/work, CI=1 are passed. GH_TOKEN, GITHUB_TOKEN, SSH_AUTH_SOCK never reach argv |
|
|
26
26
|
| Mounts | exactly one: the repo, read-only. No HOME, no docker socket, no output mount |
|
|
27
27
|
| Output | stdout is captured by the host, capped in-container (`--max-output`); the host writes result.json and output.txt |
|
|
28
|
+
| Report | `--report /work/NAME` returns the file the check's runner wrote there (up to 1 MiB, outside the output cap) between nonce-bearing markers; the host writes it as report.txt. verify-pr runs bun test, pytest, jest and vitest with a report flag and a random path, and reads pass/fail only from that file |
|
|
28
29
|
|
|
29
30
|
Deviation from the card: there is no mounted output dir. A writable host mount would let the checked code fill the host disk, so the result travels on stdout and only the host writes `OUT`. Numeric flags are forced to base 10 (a leading zero is not octal) and every value flag requires a value. `--image` is restricted to `[A-Za-z0-9._/:@-]`.
|
|
30
31
|
|
|
@@ -35,6 +36,7 @@ Deviation from the card: there is no mounted output dir. A writable host mount w
|
|
|
35
36
|
- Oversized output: capped by `--max-output`; `output_truncated` is set.
|
|
36
37
|
- Fork bomb: `--pids-limit 256`. Memory bomb: `--memory`. Disk fill: tmpfs size caps.
|
|
37
38
|
- Forged result: the checked code can print a fake `LOKI_VPR_END` line. A per-run 128-bit nonce is sent to the wrapper on stdin and the checked command runs with stdin from /dev/null; the host accepts only the last line carrying that nonce. Docker's default seccomp profile does NOT block ptrace or process_vm_readv on kernels >= 4.8, and the checked command runs as the same uid as the wrapper inside the container, so a hostile process can read the wrapper's memory and recover the nonce. The nonce therefore only stops accidental or naive forgery; it is not a security boundary. One cross-check is added: the wrapper exits with the check's code and the host rejects (status ERROR) a sentinel that disagrees with docker's own exit code. The PR code can still make its own check report success, which is why `result.json` is a signal about the check and not the final verdict (VPR-2 owns that, and it must not treat a bare COMPLETED exit 0 as proof). A custom seccomp profile denying ptrace is a possible hardening and is not shipped here.
|
|
39
|
+
- Forged report: the report path is a per-run random name given only on the runner's command line, so printed totals cannot forge it. A hostile test that reads its parent's command line (or the nonce, see above) and rewrites the file after the runner exits can still forge a pass; the same ptrace-class residual applies.
|
|
38
40
|
- Docker pool exhaustion: reported as BLOCKED, never as a failing check.
|
|
39
41
|
|
|
40
42
|
## Not covered (residual, tracked for VPR-2 review)
|