loki-mode 9.22.9 → 9.22.11
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/README.md +13 -0
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/issue-parser.sh +30 -1
- package/autonomy/lib/proof-generator.py +13 -2
- package/autonomy/lib/proof-pr.sh +6 -1
- package/autonomy/loki +107 -3
- package/dashboard/__init__.py +1 -1
- package/dashboard/static/index.html +91 -27
- package/docs/INSTALLATION.md +1 -1
- package/loki-ts/dist/loki.js +442 -442
- package/mcp/__init__.py +1 -1
- package/package.json +1 -1
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/providers/model_catalog.json +86 -1
package/README.md
CHANGED
|
@@ -399,6 +399,19 @@ honest verdict (VERIFIED / VERIFIED WITH GAPS / NOT VERIFIED), the key facts
|
|
|
399
399
|
only when the receipt's own headline is VERIFIED. This is on by default whenever
|
|
400
400
|
Loki opens or advises a PR; opt out with `LOKI_PROVEN_PR=0`.
|
|
401
401
|
|
|
402
|
+
For a review-before-publish workflow, preparation and GitHub mutation are two
|
|
403
|
+
explicit steps:
|
|
404
|
+
|
|
405
|
+
```bash
|
|
406
|
+
loki start owner/repo#42 --prepare-pr # builds and writes exact title/body locally
|
|
407
|
+
loki ship --publish # pushes that issue branch and opens the PR
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
The second command consumes `.loki/state/pr-title.txt` and
|
|
411
|
+
`.loki/state/pr-body.md` byte-for-byte. Plain `loki ship`, previews, and default
|
|
412
|
+
start paths remain non-publishing. A failed PR creation preserves both files and
|
|
413
|
+
prints the exact remote-branch rollback command.
|
|
414
|
+
|
|
402
415
|
An optional advisory status check (`loki: verified-completion`) maps the verdict
|
|
403
416
|
to a GitHub check-run. It is opt-in (`LOKI_PROVEN_PR_CHECK=1`) and can never block
|
|
404
417
|
a merge on its own. To make verified-completion blocking, add it as a required
|
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.22.
|
|
6
|
+
# Loki Mode v9.22.11
|
|
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.22.
|
|
473
|
+
**v9.22.11 | [Autonomi](https://www.autonomi.dev/) flagship product | ~410 lines core**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
9.22.
|
|
1
|
+
9.22.11
|
package/autonomy/issue-parser.sh
CHANGED
|
@@ -265,7 +265,7 @@ _gp_criteria_lines() {
|
|
|
265
265
|
}
|
|
266
266
|
|
|
267
267
|
# write_journey_context <owner> <repo> <number> <title> <url> <acceptance>
|
|
268
|
-
# <files> <type> <priority>
|
|
268
|
+
# <files> <type> <priority> [journey-start-epoch]
|
|
269
269
|
#
|
|
270
270
|
# Writes .loki/state/issue-context.json (feature 2: the exact acceptance context)
|
|
271
271
|
# and .loki/state/journey-plan.json (feature 3: the early machine-readable
|
|
@@ -277,6 +277,7 @@ _gp_criteria_lines() {
|
|
|
277
277
|
write_journey_context() {
|
|
278
278
|
local owner="$1" repo="$2" number="$3" title="$4" url="$5"
|
|
279
279
|
local acceptance="$6" files="$7" issue_type="$8" priority="$9"
|
|
280
|
+
local journey_started_epoch="${10:-}"
|
|
280
281
|
|
|
281
282
|
local state_dir="${LOKI_DIR:-.loki}/state"
|
|
282
283
|
mkdir -p "$state_dir" 2>/dev/null || return 0
|
|
@@ -348,6 +349,34 @@ write_journey_context() {
|
|
|
348
349
|
rm -f "$plan_tmp" 2>/dev/null || true
|
|
349
350
|
fi
|
|
350
351
|
|
|
352
|
+
# The parsed, acceptance-bound plan is the first useful result: it tells the
|
|
353
|
+
# user what Loki understood and what it will attempt before provider latency
|
|
354
|
+
# begins. Measure it honestly from command entry when the caller supplied a
|
|
355
|
+
# valid epoch. This is explicitly a proposed plan, never represented as a
|
|
356
|
+
# verified patch. Later first-artifact evidence supersedes it in receipts.
|
|
357
|
+
case "$journey_started_epoch" in
|
|
358
|
+
''|*[!0-9]*) ;;
|
|
359
|
+
*)
|
|
360
|
+
local now_epoch elapsed first_tmp
|
|
361
|
+
now_epoch="$(date +%s)"
|
|
362
|
+
elapsed=$((now_epoch >= journey_started_epoch ? now_epoch - journey_started_epoch : 0))
|
|
363
|
+
first_tmp="$state_dir/.first-useful-result.$$.json"
|
|
364
|
+
if jq -n --argjson seconds "$elapsed" \
|
|
365
|
+
--arg generated_at "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
|
366
|
+
'{schema_version:"1.0", kind:"proposed_solution_plan",
|
|
367
|
+
seconds_to_first_result:$seconds,
|
|
368
|
+
under_60_seconds:($seconds < 60),
|
|
369
|
+
verified_patch:false, generated_at:$generated_at,
|
|
370
|
+
artifact:".loki/state/journey-plan.json"}' \
|
|
371
|
+
> "$first_tmp" 2>/dev/null; then
|
|
372
|
+
mv -f "$first_tmp" "$state_dir/first-useful-result.json" 2>/dev/null \
|
|
373
|
+
|| rm -f "$first_tmp"
|
|
374
|
+
else
|
|
375
|
+
rm -f "$first_tmp" 2>/dev/null || true
|
|
376
|
+
fi
|
|
377
|
+
;;
|
|
378
|
+
esac
|
|
379
|
+
|
|
351
380
|
return 0
|
|
352
381
|
}
|
|
353
382
|
|
|
@@ -1031,13 +1031,24 @@ def _collect_journey(loki_dir):
|
|
|
1031
1031
|
},
|
|
1032
1032
|
}
|
|
1033
1033
|
|
|
1034
|
-
# Time to first useful result.
|
|
1035
|
-
#
|
|
1034
|
+
# Time to first useful result. Prefer the first verified code artifact when
|
|
1035
|
+
# one exists. Before that, issue mode can truthfully report its acceptance-
|
|
1036
|
+
# bound proposed plan, explicitly labelled as NOT a verified patch.
|
|
1036
1037
|
fa = _read_json(os.path.join(state, "first-artifact.json"), default=None)
|
|
1037
1038
|
if isinstance(fa, dict):
|
|
1038
1039
|
v = fa.get("seconds_to_first_artifact")
|
|
1039
1040
|
if isinstance(v, (int, float)) and v >= 0:
|
|
1040
1041
|
out["time_to_first_result_sec"] = int(v)
|
|
1042
|
+
out["first_result_kind"] = "code_change"
|
|
1043
|
+
out["first_result_verified_patch"] = True
|
|
1044
|
+
else:
|
|
1045
|
+
fr = _read_json(os.path.join(state, "first-useful-result.json"), default=None)
|
|
1046
|
+
if isinstance(fr, dict):
|
|
1047
|
+
v = fr.get("seconds_to_first_result")
|
|
1048
|
+
if isinstance(v, (int, float)) and v >= 0:
|
|
1049
|
+
out["time_to_first_result_sec"] = int(v)
|
|
1050
|
+
out["first_result_kind"] = str(fr.get("kind") or "")
|
|
1051
|
+
out["first_result_verified_patch"] = bool(fr.get("verified_patch") is True)
|
|
1041
1052
|
|
|
1042
1053
|
# Human interventions. Fills the socket trust_trajectory.py:145 already
|
|
1043
1054
|
# reads and documents as "no per-run counter persisted today". Absent file
|
package/autonomy/lib/proof-pr.sh
CHANGED
|
@@ -220,7 +220,12 @@ def main():
|
|
|
220
220
|
|
|
221
221
|
ttfr = journey.get("time_to_first_result_sec")
|
|
222
222
|
if isinstance(ttfr, int):
|
|
223
|
-
|
|
223
|
+
first_kind = str(journey.get("first_result_kind") or "").strip()
|
|
224
|
+
if first_kind == "proposed_solution_plan":
|
|
225
|
+
_line("| First useful result | proposed plan in " + str(ttfr)
|
|
226
|
+
+ "s (not a verified patch) |")
|
|
227
|
+
else:
|
|
228
|
+
_line("| Time to first result | " + str(ttfr) + "s |")
|
|
224
229
|
|
|
225
230
|
ivs = journey.get("interventions")
|
|
226
231
|
if isinstance(ivs, int):
|
package/autonomy/loki
CHANGED
|
@@ -4617,6 +4617,89 @@ cmd_next() {
|
|
|
4617
4617
|
}
|
|
4618
4618
|
|
|
4619
4619
|
# loki ship -- the build is done, now get it out (review + PR advice in one flow).
|
|
4620
|
+
# Publish an already-prepared PR. This is deliberately a separate, explicit
|
|
4621
|
+
# mutation boundary from the default print-only `loki ship` flow. Preparation
|
|
4622
|
+
# writes the exact reviewed title/body under .loki/state; publishing consumes
|
|
4623
|
+
# those bytes without rebuilding, re-rendering, or inventing evidence.
|
|
4624
|
+
publish_prepared_pr() {
|
|
4625
|
+
local state_dir="${LOKI_DIR:-.loki}/state"
|
|
4626
|
+
local title_file="$state_dir/pr-title.txt"
|
|
4627
|
+
local body_file="$state_dir/pr-body.md"
|
|
4628
|
+
local pr_state="$state_dir/pr.json"
|
|
4629
|
+
|
|
4630
|
+
if [ ! -s "$title_file" ] || [ ! -s "$body_file" ]; then
|
|
4631
|
+
echo "Error: no prepared PR found. Run 'loki start <issue> --prepare-pr' first." >&2
|
|
4632
|
+
return 2
|
|
4633
|
+
fi
|
|
4634
|
+
if ! command -v git >/dev/null 2>&1 || ! git rev-parse --git-dir >/dev/null 2>&1; then
|
|
4635
|
+
echo "Error: publishing a prepared PR requires a git repository." >&2
|
|
4636
|
+
return 2
|
|
4637
|
+
fi
|
|
4638
|
+
if ! command -v gh >/dev/null 2>&1; then
|
|
4639
|
+
echo "Error: publishing a prepared PR requires the GitHub CLI (gh)." >&2
|
|
4640
|
+
return 2
|
|
4641
|
+
fi
|
|
4642
|
+
|
|
4643
|
+
local branch base title existing_url pr_url tmp_state
|
|
4644
|
+
branch="$(git rev-parse --abbrev-ref HEAD 2>/dev/null || true)"
|
|
4645
|
+
case "$branch" in
|
|
4646
|
+
""|HEAD|main|master)
|
|
4647
|
+
echo "Error: refusing to publish prepared work from '$branch'; check out its issue branch." >&2
|
|
4648
|
+
return 2 ;;
|
|
4649
|
+
esac
|
|
4650
|
+
if ! git remote get-url origin >/dev/null 2>&1; then
|
|
4651
|
+
echo "Error: publishing a prepared PR requires an 'origin' remote." >&2
|
|
4652
|
+
return 2
|
|
4653
|
+
fi
|
|
4654
|
+
title="$(cat "$title_file")"
|
|
4655
|
+
if [ -z "$title" ]; then
|
|
4656
|
+
echo "Error: prepared PR title must be one non-empty line." >&2
|
|
4657
|
+
return 2
|
|
4658
|
+
fi
|
|
4659
|
+
case "$title" in
|
|
4660
|
+
*$'\n'*)
|
|
4661
|
+
echo "Error: prepared PR title must be one non-empty line." >&2
|
|
4662
|
+
return 2 ;;
|
|
4663
|
+
esac
|
|
4664
|
+
|
|
4665
|
+
# Idempotence: an interrupted/retried publish reuses the open PR and never
|
|
4666
|
+
# creates a duplicate. This read-only query occurs only after --publish.
|
|
4667
|
+
existing_url="$(gh pr list --head "$branch" --state open --json url --jq '.[0].url // empty' 2>/dev/null || true)"
|
|
4668
|
+
if [ -n "$existing_url" ]; then
|
|
4669
|
+
pr_url="$existing_url"
|
|
4670
|
+
else
|
|
4671
|
+
# Do not attempt PR creation after a failed push. The prepared body
|
|
4672
|
+
# remains local and byte-identical, so the operator can fix auth/network
|
|
4673
|
+
# and retry. A successful push followed by create failure is reversible
|
|
4674
|
+
# with the exact command printed below.
|
|
4675
|
+
if ! git push --set-upstream origin "$branch"; then
|
|
4676
|
+
echo "Error: branch push failed; prepared PR files were preserved." >&2
|
|
4677
|
+
return 1
|
|
4678
|
+
fi
|
|
4679
|
+
if ! pr_url="$(gh pr create --head "$branch" --title "$title" --body-file "$body_file")"; then
|
|
4680
|
+
echo "Error: PR creation failed; prepared PR files were preserved." >&2
|
|
4681
|
+
echo "Rollback remote branch: git push origin --delete $branch" >&2
|
|
4682
|
+
return 1
|
|
4683
|
+
fi
|
|
4684
|
+
pr_url="$(printf '%s\n' "$pr_url" | grep -Eo 'https://[^[:space:]]+' | head -1)"
|
|
4685
|
+
if [ -z "$pr_url" ]; then
|
|
4686
|
+
echo "Error: gh reported success without a PR URL; prepared files were preserved." >&2
|
|
4687
|
+
echo "Inspect: gh pr list --head $branch" >&2
|
|
4688
|
+
return 1
|
|
4689
|
+
fi
|
|
4690
|
+
fi
|
|
4691
|
+
|
|
4692
|
+
mkdir -p "$state_dir" || return 1
|
|
4693
|
+
tmp_state="$pr_state.tmp.$$"
|
|
4694
|
+
if command -v jq >/dev/null 2>&1; then
|
|
4695
|
+
jq -n --arg url "$pr_url" --arg branch "$branch" --arg title "$title" \
|
|
4696
|
+
'{state:"created", url:$url, branch:$branch, title:$title,
|
|
4697
|
+
body_path:".loki/state/pr-body.md"}' > "$tmp_state" \
|
|
4698
|
+
&& mv "$tmp_state" "$pr_state" || { rm -f "$tmp_state"; return 1; }
|
|
4699
|
+
fi
|
|
4700
|
+
echo "PR ready: $pr_url"
|
|
4701
|
+
}
|
|
4702
|
+
|
|
4620
4703
|
# Composes existing surfaces only: optionally opens the running app (--preview),
|
|
4621
4704
|
# runs the SAME diff quality gates as cmd_review, and on a clean-enough result
|
|
4622
4705
|
# prints the exact branch-aware PR command via the shared print_pr_advice (the
|
|
@@ -4626,6 +4709,7 @@ cmd_next() {
|
|
|
4626
4709
|
# and points at the findings instead of advising a PR.
|
|
4627
4710
|
cmd_ship() {
|
|
4628
4711
|
local do_preview=false
|
|
4712
|
+
local publish=false
|
|
4629
4713
|
local review_args=()
|
|
4630
4714
|
# Tracks whether the caller passed an explicit scope flag (--staged, --since,
|
|
4631
4715
|
# ...). Passthrough flags like --yes/--severity do NOT set this, so they do
|
|
@@ -4637,6 +4721,7 @@ cmd_ship() {
|
|
|
4637
4721
|
echo -e "${BOLD}Loki Mode -- finish the build: review, then PR advice (print-only)${NC}"
|
|
4638
4722
|
echo ""
|
|
4639
4723
|
echo "Usage: loki ship [--preview] [--yes] [review options]"
|
|
4724
|
+
echo " loki ship --publish"
|
|
4640
4725
|
echo ""
|
|
4641
4726
|
echo "Runs the natural finish line in one command:"
|
|
4642
4727
|
echo " 1. (with --preview) opens the app Loki built and started locally"
|
|
@@ -4645,13 +4730,15 @@ cmd_ship() {
|
|
|
4645
4730
|
echo " 3. on a clean-enough result, PRINTS the exact branch-aware"
|
|
4646
4731
|
echo " git push + pull-request command for YOU to run"
|
|
4647
4732
|
echo ""
|
|
4648
|
-
echo "
|
|
4649
|
-
echo "creates a PR
|
|
4733
|
+
echo "The default flow is advisory only: it NEVER runs 'git push' or"
|
|
4734
|
+
echo "creates a PR. --publish is the explicit mutation boundary: it"
|
|
4735
|
+
echo "publishes the exact title/body previously written by --prepare-pr."
|
|
4650
4736
|
echo "If review finds HIGH or CRITICAL findings it stops and points you"
|
|
4651
4737
|
echo "at the findings instead of advising a PR (exit code 1)."
|
|
4652
4738
|
echo ""
|
|
4653
4739
|
echo "Options:"
|
|
4654
4740
|
echo " --preview Open the running local app first (loki preview)"
|
|
4741
|
+
echo " --publish Push the current issue branch and publish its prepared PR"
|
|
4655
4742
|
echo " --yes, -y Pass through to review (skip its confirmation prompt)"
|
|
4656
4743
|
echo " --help, -h Show this help and exit"
|
|
4657
4744
|
echo ""
|
|
@@ -4660,6 +4747,7 @@ cmd_ship() {
|
|
|
4660
4747
|
return 0
|
|
4661
4748
|
;;
|
|
4662
4749
|
--preview) do_preview=true ;;
|
|
4750
|
+
--publish) publish=true ;;
|
|
4663
4751
|
# Only a known set of NON-scope passthrough flags are exempt from
|
|
4664
4752
|
# "explicit scope". Everything else the caller passes -- an explicit
|
|
4665
4753
|
# scope flag (--staged/--since/...), a positional <file-or-dir>, or any
|
|
@@ -4689,6 +4777,15 @@ cmd_ship() {
|
|
|
4689
4777
|
shift
|
|
4690
4778
|
done
|
|
4691
4779
|
|
|
4780
|
+
if [ "$publish" = true ]; then
|
|
4781
|
+
if [ "$do_preview" = true ] || [ "${#review_args[@]}" -gt 0 ]; then
|
|
4782
|
+
echo "Error: --publish cannot be combined with preview/review options." >&2
|
|
4783
|
+
return 2
|
|
4784
|
+
fi
|
|
4785
|
+
publish_prepared_pr
|
|
4786
|
+
return $?
|
|
4787
|
+
fi
|
|
4788
|
+
|
|
4692
4789
|
# 1. Optional preview of the running local app. Only when an app-runner state
|
|
4693
4790
|
# file exists, so we never imply an app is running when it is not.
|
|
4694
4791
|
if [ "$do_preview" = true ]; then
|
|
@@ -9694,6 +9791,12 @@ cmd_issue_view() {
|
|
|
9694
9791
|
#===============================================================================
|
|
9695
9792
|
|
|
9696
9793
|
cmd_run() {
|
|
9794
|
+
# Wall-clock anchor for the issue journey. Captured before argument parsing,
|
|
9795
|
+
# auth, or issue fetch so the first-result measurement includes the wait the
|
|
9796
|
+
# user actually experiences. Exported only through the explicit writer call
|
|
9797
|
+
# below; it does not alter runner/provider behavior.
|
|
9798
|
+
local _issue_journey_started_epoch
|
|
9799
|
+
_issue_journey_started_epoch="$(date +%s)"
|
|
9697
9800
|
# v6.84.0: `loki run` is now a deprecated alias for `loki start <issue-ref>`.
|
|
9698
9801
|
# When invoked directly (not via the unified start dispatcher), emit a
|
|
9699
9802
|
# deprecation notice and a telemetry event so we can track adoption of the
|
|
@@ -10060,7 +10163,8 @@ cmd_run() {
|
|
|
10060
10163
|
_gp_acc=$(extract_acceptance_criteria "$_gp_body" 2>/dev/null || true)
|
|
10061
10164
|
fi
|
|
10062
10165
|
write_journey_context "$_gp_owner" "$_gp_repo" "${number:-}" "$title" \
|
|
10063
|
-
"$url" "$_gp_acc" "" "${issue_provider:-github}" ""
|
|
10166
|
+
"$url" "$_gp_acc" "" "${issue_provider:-github}" "" \
|
|
10167
|
+
"$_issue_journey_started_epoch" 2>/dev/null || true
|
|
10064
10168
|
fi
|
|
10065
10169
|
|
|
10066
10170
|
# Per-session locking (v6.4.0): export session ID so run.sh uses
|