loki-mode 9.47.0 → 9.48.2
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 +105 -0
- package/.github/workflows/loki-issue-to-pr.yml +87 -0
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/loki +93 -8
- package/autonomy/run.sh +20 -0
- package/dashboard/__init__.py +1 -1
- package/docs/INSTALLATION.md +1 -1
- package/loki-ts/dist/loki.js +2 -2
- package/mcp/__init__.py +1 -1
- package/package.json +3 -1
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
name: 'Loki Issue to PR'
|
|
2
|
+
description: 'Hand Loki Mode a GitHub issue; it opens a pull request with a verifiable evidence receipt.'
|
|
3
|
+
author: 'asklokesh'
|
|
4
|
+
|
|
5
|
+
branding:
|
|
6
|
+
icon: 'git-pull-request'
|
|
7
|
+
color: 'purple'
|
|
8
|
+
|
|
9
|
+
inputs:
|
|
10
|
+
issue:
|
|
11
|
+
description: 'Issue reference. Defaults to the issue that triggered this workflow.'
|
|
12
|
+
required: false
|
|
13
|
+
default: ''
|
|
14
|
+
provider:
|
|
15
|
+
description: 'AI provider: claude, codex, cline, aider, or opencode'
|
|
16
|
+
required: false
|
|
17
|
+
default: 'claude'
|
|
18
|
+
budget_limit:
|
|
19
|
+
description: 'Max spend in USD before the run pauses. Breaching PAUSES; it never discards work.'
|
|
20
|
+
required: false
|
|
21
|
+
default: '10.00'
|
|
22
|
+
max_iterations:
|
|
23
|
+
description: 'Hard ceiling on RARV iterations.'
|
|
24
|
+
required: false
|
|
25
|
+
default: '20'
|
|
26
|
+
version:
|
|
27
|
+
description: 'loki-mode version to install. Pin this for reproducible runs.'
|
|
28
|
+
required: false
|
|
29
|
+
default: 'latest'
|
|
30
|
+
|
|
31
|
+
outputs:
|
|
32
|
+
pr_url:
|
|
33
|
+
description: 'URL of the pull request Loki opened, empty if none was opened.'
|
|
34
|
+
value: ${{ steps.run.outputs.pr_url }}
|
|
35
|
+
|
|
36
|
+
runs:
|
|
37
|
+
using: 'composite'
|
|
38
|
+
steps:
|
|
39
|
+
- name: Install Loki Mode
|
|
40
|
+
shell: bash
|
|
41
|
+
run: npm install -g loki-mode@${{ inputs.version }}
|
|
42
|
+
|
|
43
|
+
- name: Resolve the issue reference
|
|
44
|
+
id: ref
|
|
45
|
+
shell: bash
|
|
46
|
+
run: |
|
|
47
|
+
# Prefer the explicit input; otherwise use the triggering issue. Failing
|
|
48
|
+
# CLOSED here is deliberate: a run with no issue would otherwise start
|
|
49
|
+
# from the repository's own state and produce an unrelated PR.
|
|
50
|
+
REF="${{ inputs.issue }}"
|
|
51
|
+
if [ -z "$REF" ]; then
|
|
52
|
+
NUM="${{ github.event.issue.number }}"
|
|
53
|
+
if [ -z "$NUM" ]; then
|
|
54
|
+
echo "::error::No issue to work on. Pass the 'issue' input, or trigger this action from an issue event."
|
|
55
|
+
exit 1
|
|
56
|
+
fi
|
|
57
|
+
REF="${{ github.repository }}#${NUM}"
|
|
58
|
+
fi
|
|
59
|
+
echo "ref=$REF" >> "$GITHUB_OUTPUT"
|
|
60
|
+
echo "Resolved issue reference: $REF"
|
|
61
|
+
|
|
62
|
+
- name: Resolve the issue to a pull request
|
|
63
|
+
id: run
|
|
64
|
+
shell: bash
|
|
65
|
+
env:
|
|
66
|
+
# gh is what opens the PR. Without a token the run still builds and the
|
|
67
|
+
# PR step no-ops, so this is not fatal, but it IS the common misconfig.
|
|
68
|
+
GH_TOKEN: ${{ github.token }}
|
|
69
|
+
LOKI_PROVIDER: ${{ inputs.provider }}
|
|
70
|
+
LOKI_BUDGET_LIMIT: ${{ inputs.budget_limit }}
|
|
71
|
+
LOKI_MAX_ITERATIONS: ${{ inputs.max_iterations }}
|
|
72
|
+
# The PR is the deliverable, so the PR path is on. Default-on since
|
|
73
|
+
# v9.43.0; set explicitly here so the action does not depend on the
|
|
74
|
+
# installed version's default.
|
|
75
|
+
LOKI_DELEGATE_PR: '1'
|
|
76
|
+
run: |
|
|
77
|
+
set -uo pipefail
|
|
78
|
+
|
|
79
|
+
# git identity: gh pr create needs commits to have an author.
|
|
80
|
+
git config user.name "${GITHUB_ACTOR:-loki-mode}"
|
|
81
|
+
git config user.email "${GITHUB_ACTOR:-loki-mode}@users.noreply.github.com"
|
|
82
|
+
|
|
83
|
+
loki start "${{ steps.ref.outputs.ref }}" || RC=$?
|
|
84
|
+
RC="${RC:-0}"
|
|
85
|
+
|
|
86
|
+
# Report the PR if one was opened. Read it from the state Loki writes
|
|
87
|
+
# rather than re-deriving it, so this reports what ACTUALLY happened.
|
|
88
|
+
PR_URL=""
|
|
89
|
+
if [ -f .loki/state/pr-url.txt ]; then
|
|
90
|
+
PR_URL="$(cat .loki/state/pr-url.txt 2>/dev/null || true)"
|
|
91
|
+
fi
|
|
92
|
+
echo "pr_url=$PR_URL" >> "$GITHUB_OUTPUT"
|
|
93
|
+
|
|
94
|
+
if [ -n "$PR_URL" ]; then
|
|
95
|
+
echo "Pull request: $PR_URL"
|
|
96
|
+
else
|
|
97
|
+
echo "::warning::No pull request was opened. Check that gh is authenticated, the branch is not a default branch, and the run produced changes."
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
# Surface the receipt path so a reviewer can check the evidence.
|
|
101
|
+
if [ -d .loki/proofs ]; then
|
|
102
|
+
echo "Evidence receipts under .loki/proofs/"
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
exit "$RC"
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Hand Loki an issue, get a pull request.
|
|
2
|
+
#
|
|
3
|
+
# Label an issue `loki` (or comment `/loki`) and this opens a PR with an
|
|
4
|
+
# evidence receipt. Copy this file into .github/workflows/ of any repository.
|
|
5
|
+
#
|
|
6
|
+
# REQUIRED: set ANTHROPIC_API_KEY in repository secrets. Without it the run
|
|
7
|
+
# cannot call a model and fails fast rather than burning minutes.
|
|
8
|
+
name: Loki - Issue to PR
|
|
9
|
+
|
|
10
|
+
on:
|
|
11
|
+
issues:
|
|
12
|
+
types: [labeled]
|
|
13
|
+
issue_comment:
|
|
14
|
+
types: [created]
|
|
15
|
+
workflow_dispatch:
|
|
16
|
+
inputs:
|
|
17
|
+
issue:
|
|
18
|
+
description: 'Issue number to resolve'
|
|
19
|
+
required: true
|
|
20
|
+
|
|
21
|
+
# Serialize per issue. Two agents racing on one issue would open two PRs from
|
|
22
|
+
# two branches and neither would see the other's work.
|
|
23
|
+
concurrency:
|
|
24
|
+
group: loki-issue-${{ github.event.issue.number || inputs.issue }}
|
|
25
|
+
cancel-in-progress: false
|
|
26
|
+
|
|
27
|
+
permissions:
|
|
28
|
+
contents: write # push the agent branch
|
|
29
|
+
pull-requests: write # open the PR
|
|
30
|
+
issues: read
|
|
31
|
+
|
|
32
|
+
jobs:
|
|
33
|
+
resolve:
|
|
34
|
+
# Gate on an explicit signal so the agent never fires on unrelated activity.
|
|
35
|
+
if: >-
|
|
36
|
+
(github.event_name == 'issues' && github.event.label.name == 'loki') ||
|
|
37
|
+
(github.event_name == 'issue_comment' && startsWith(github.event.comment.body, '/loki')) ||
|
|
38
|
+
github.event_name == 'workflow_dispatch'
|
|
39
|
+
runs-on: ubuntu-latest
|
|
40
|
+
timeout-minutes: 45
|
|
41
|
+
steps:
|
|
42
|
+
- uses: actions/checkout@v4
|
|
43
|
+
with:
|
|
44
|
+
fetch-depth: 0 # the agent branches and diffs; a shallow clone breaks both
|
|
45
|
+
|
|
46
|
+
- uses: actions/setup-node@v4
|
|
47
|
+
with:
|
|
48
|
+
node-version: '20'
|
|
49
|
+
|
|
50
|
+
- name: Fail fast without a model key
|
|
51
|
+
env:
|
|
52
|
+
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
53
|
+
run: |
|
|
54
|
+
if [ -z "${ANTHROPIC_API_KEY:-}" ]; then
|
|
55
|
+
echo "::error::ANTHROPIC_API_KEY is not set in repository secrets. Add it under Settings > Secrets and variables > Actions."
|
|
56
|
+
exit 1
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
- name: Resolve the issue
|
|
60
|
+
id: loki
|
|
61
|
+
# Pinned to a TAG, not @main. A moving ref would hand every user
|
|
62
|
+
# whatever main holds at the moment their issue is labeled, including a
|
|
63
|
+
# half-landed release. Bump this line deliberately.
|
|
64
|
+
uses: asklokesh/loki-mode/.github/actions/issue-to-pr@v9.48.2
|
|
65
|
+
env:
|
|
66
|
+
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
67
|
+
with:
|
|
68
|
+
issue: ${{ github.event.issue.number || inputs.issue }}
|
|
69
|
+
budget_limit: '10.00'
|
|
70
|
+
|
|
71
|
+
- name: Report back on the issue
|
|
72
|
+
if: always() && steps.loki.outputs.pr_url != ''
|
|
73
|
+
env:
|
|
74
|
+
GH_TOKEN: ${{ github.token }}
|
|
75
|
+
PR_URL: ${{ steps.loki.outputs.pr_url }}
|
|
76
|
+
ISSUE: ${{ github.event.issue.number || inputs.issue }}
|
|
77
|
+
run: |
|
|
78
|
+
# Build the body in a file: a blank line inside an inline YAML string
|
|
79
|
+
# terminates the block scalar and breaks the workflow parse.
|
|
80
|
+
{
|
|
81
|
+
echo "Loki opened a pull request: $PR_URL"
|
|
82
|
+
echo ""
|
|
83
|
+
echo "The PR body carries an evidence receipt stating what was verified,"
|
|
84
|
+
echo "what was skipped, and what is degraded. Check it rather than taking"
|
|
85
|
+
echo "the result on trust."
|
|
86
|
+
} > /tmp/loki-issue-comment.md
|
|
87
|
+
gh issue comment "$ISSUE" --body-file /tmp/loki-issue-comment.md || true
|
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.48.2
|
|
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.48.2 | [Autonomi](https://www.autonomi.dev/) flagship product | ~410 lines core**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
9.
|
|
1
|
+
9.48.2
|
package/autonomy/loki
CHANGED
|
@@ -4502,10 +4502,27 @@ cmd_steer() {
|
|
|
4502
4502
|
# duplicating them here would contradict it.
|
|
4503
4503
|
#
|
|
4504
4504
|
# Read-only: reads state, writes nothing, spends nothing.
|
|
4505
|
+
# Print the "you can pick this up" hint for a run that STOPPED WITHOUT A VERDICT.
|
|
4506
|
+
#
|
|
4507
|
+
# THE DEFECT this widening fixes, reproduced: cmd_next maps
|
|
4508
|
+
# max_iterations_reached and budget_exceeded to `loki resume`, but this helper
|
|
4509
|
+
# accepted ONLY "interrupted", so cmd_resume fell through to "No session to
|
|
4510
|
+
# resume. Start a session with: loki start" -- rc=0. The two commands whose
|
|
4511
|
+
# whole job is "do the right next thing" contradicted each other on every run
|
|
4512
|
+
# that hit a limit.
|
|
4513
|
+
#
|
|
4514
|
+
# WHAT MUST NOT BE ADDED HERE: council_approved, council_force_approved and
|
|
4515
|
+
# completion_promise_fulfilled. Those carry a VERDICT and route to `loki ship`.
|
|
4516
|
+
# Accepting them would send an approved build back into the loop.
|
|
4517
|
+
# failed / policy_blocked / force_stopped route to `loki why` and stay out too.
|
|
4518
|
+
# The set below is exactly "stopped on a limit, no verdict reached".
|
|
4505
4519
|
_loki_print_interrupted_resume_hint() {
|
|
4506
4520
|
local status
|
|
4507
4521
|
status="$(_loki_resolve_run_status 2>/dev/null)" || return 1
|
|
4508
|
-
|
|
4522
|
+
case "$status" in
|
|
4523
|
+
interrupted|max_iterations_reached|budget_exceeded) ;;
|
|
4524
|
+
*) return 1 ;;
|
|
4525
|
+
esac
|
|
4509
4526
|
|
|
4510
4527
|
local state_file="$LOKI_DIR/autonomy-state.json"
|
|
4511
4528
|
if [ -n "${LOKI_SESSION_ID:-}" ] && [ -f "$LOKI_DIR/sessions/${LOKI_SESSION_ID}/autonomy-state.json" ]; then
|
|
@@ -4542,12 +4559,52 @@ print('\t'.join([
|
|
|
4542
4559
|
resume_cmd="loki start \"$prd_path\""
|
|
4543
4560
|
fi
|
|
4544
4561
|
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4562
|
+
# A capped run needs DIFFERENT advice than an interrupted one: re-running it
|
|
4563
|
+
# unchanged hits the very same limit on the next iteration. cmd_next's
|
|
4564
|
+
# action_text already says to raise the cap first; saying less here would
|
|
4565
|
+
# move the contradiction rather than close it.
|
|
4566
|
+
case "$status" in
|
|
4567
|
+
max_iterations_reached)
|
|
4568
|
+
# Deliberately does NOT print the iteration it reached.
|
|
4569
|
+
# `load_state` resets ITERATION_COUNT=0 for this terminal status
|
|
4570
|
+
# (autonomy/run.sh, the failure-terminals case arm), so a fresh
|
|
4571
|
+
# `loki start` is a NEW session from iteration 0. Advertising the
|
|
4572
|
+
# old number would promise a continuation the runtime will not
|
|
4573
|
+
# honour -- the exact false claim tests/test-resume-discoverability.sh
|
|
4574
|
+
# guards, and it caught this in CI.
|
|
4575
|
+
echo -e "${YELLOW}Iteration limit reached.${NC} (last activity: ${last_run})."
|
|
4576
|
+
echo "The committed work is intact, but this starts a NEW session from"
|
|
4577
|
+
echo "iteration 0 -- it does not continue the old count."
|
|
4578
|
+
echo "Raise the cap (or narrow the spec), then run:"
|
|
4579
|
+
echo ""
|
|
4580
|
+
echo -e " ${BOLD}LOKI_MAX_ITERATIONS=<higher> ${resume_cmd}${NC}"
|
|
4581
|
+
;;
|
|
4582
|
+
budget_exceeded)
|
|
4583
|
+
# Same reasoning as max_iterations_reached: this terminal status is
|
|
4584
|
+
# in load_state's reset list, so the prior iteration count is gone.
|
|
4585
|
+
echo -e "${YELLOW}Budget limit reached.${NC} (last activity: ${last_run})."
|
|
4586
|
+
echo "The committed work is intact, but this starts a NEW session from"
|
|
4587
|
+
echo "iteration 0 -- it does not continue the old count."
|
|
4588
|
+
echo "Raise the budget (or narrow the spec), then run:"
|
|
4589
|
+
echo ""
|
|
4590
|
+
echo -e " ${BOLD}LOKI_BUDGET_LIMIT=<higher> ${resume_cmd}${NC}"
|
|
4591
|
+
;;
|
|
4592
|
+
*)
|
|
4593
|
+
echo -e "${YELLOW}Interrupted run found.${NC} Stopped at iteration ${BOLD}${iteration}${NC} (last activity: ${last_run})."
|
|
4594
|
+
echo "Saved progress is intact. Resume it with:"
|
|
4595
|
+
echo ""
|
|
4596
|
+
echo -e " ${BOLD}${resume_cmd}${NC}"
|
|
4597
|
+
;;
|
|
4598
|
+
esac
|
|
4549
4599
|
echo ""
|
|
4550
|
-
|
|
4600
|
+
# Only an INTERRUPTED run actually resumes its iteration count. The capped
|
|
4601
|
+
# terminals above are reset to 0 by load_state, so the pick-up sentence must
|
|
4602
|
+
# not be printed for them.
|
|
4603
|
+
if [ "$status" = "interrupted" ]; then
|
|
4604
|
+
echo -e "${DIM}It picks up from iteration ${iteration}; verification re-runs, so nothing inherits a stale PASS.${NC}"
|
|
4605
|
+
else
|
|
4606
|
+
echo -e "${DIM}Verification re-runs from scratch, so nothing inherits a stale PASS.${NC}"
|
|
4607
|
+
fi
|
|
4551
4608
|
return 0
|
|
4552
4609
|
}
|
|
4553
4610
|
|
|
@@ -17301,12 +17358,40 @@ if manifests:
|
|
|
17301
17358
|
echo -e "${RED}Error: No repositories found matching: ${multi_repo}${NC}"
|
|
17302
17359
|
return 1
|
|
17303
17360
|
fi
|
|
17304
|
-
|
|
17361
|
+
# HONESTY: this flag DISCOVERS repositories; it does not migrate them.
|
|
17362
|
+
# `repos[]` is populated here and never referenced again -- everything
|
|
17363
|
+
# below operates on the single "$codebase_path". The old message said
|
|
17364
|
+
# "Multi-repo migration (3 repositories)" and listed all three, then
|
|
17365
|
+
# created one migration scoped to the first. A user reading that
|
|
17366
|
+
# believed three repos were migrated when one was.
|
|
17367
|
+
#
|
|
17368
|
+
# Orchestrating a real migration across repositories is a separate piece
|
|
17369
|
+
# of work (dependency order, per-repo gates, per-repo receipts). Until
|
|
17370
|
+
# that exists, this says exactly what it does and hands the user the
|
|
17371
|
+
# commands that cover the rest, rather than implying coverage it has not
|
|
17372
|
+
# delivered.
|
|
17373
|
+
local _mr_others=$((repo_count - 1))
|
|
17374
|
+
echo -e "${BOLD}Repositories found${NC} ($repo_count)"
|
|
17305
17375
|
echo "---"
|
|
17306
17376
|
for repo in "${repos[@]}"; do
|
|
17307
|
-
|
|
17377
|
+
if [ "$repo" = "$codebase_path" ]; then
|
|
17378
|
+
echo " - $repo (migrating now)"
|
|
17379
|
+
else
|
|
17380
|
+
echo " - $repo"
|
|
17381
|
+
fi
|
|
17308
17382
|
done
|
|
17309
17383
|
echo ""
|
|
17384
|
+
if [ "$_mr_others" -gt 0 ]; then
|
|
17385
|
+
echo -e "${YELLOW}--multi-repo discovers repositories; it does not migrate them together.${NC}"
|
|
17386
|
+
echo "This run migrates only: $codebase_path"
|
|
17387
|
+
echo ""
|
|
17388
|
+
echo "To cover the others, run each one:"
|
|
17389
|
+
for repo in "${repos[@]}"; do
|
|
17390
|
+
[ "$repo" = "$codebase_path" ] && continue
|
|
17391
|
+
echo " loki modernize migrate \"$repo\" --target \"$target\""
|
|
17392
|
+
done
|
|
17393
|
+
echo ""
|
|
17394
|
+
fi
|
|
17310
17395
|
fi
|
|
17311
17396
|
|
|
17312
17397
|
local migration_dir
|
package/autonomy/run.sh
CHANGED
|
@@ -5223,6 +5223,24 @@ except Exception:
|
|
|
5223
5223
|
# is already true we DEFER to that path and do nothing here, so a user who set
|
|
5224
5224
|
# both knobs never gets a double PR.
|
|
5225
5225
|
#===============================================================================
|
|
5226
|
+
# Write the PR url where an OUT-OF-PROCESS caller can read it.
|
|
5227
|
+
#
|
|
5228
|
+
# _LOKI_DELEGATE_PR_URL is exported, which reaches children but NOT a sibling
|
|
5229
|
+
# step. A GitHub composite action runs `loki start` in one step and reports the
|
|
5230
|
+
# result in the next, so an exported variable is invisible to it and the action
|
|
5231
|
+
# would have to re-derive the url and could get it wrong. Persisting it means a
|
|
5232
|
+
# caller reports what ACTUALLY happened.
|
|
5233
|
+
#
|
|
5234
|
+
# Best-effort by construction: a failure here must never affect a run whose PR
|
|
5235
|
+
# was already opened successfully.
|
|
5236
|
+
_loki_persist_pr_url() {
|
|
5237
|
+
local _u="${1:-}"
|
|
5238
|
+
[ -n "$_u" ] || return 0
|
|
5239
|
+
mkdir -p ".loki/state" 2>/dev/null || return 0
|
|
5240
|
+
printf '%s\n' "$_u" > ".loki/state/pr-url.txt" 2>/dev/null || true
|
|
5241
|
+
return 0
|
|
5242
|
+
}
|
|
5243
|
+
|
|
5226
5244
|
on_run_complete() {
|
|
5227
5245
|
# DEFAULT ON as of v9.43.0.
|
|
5228
5246
|
#
|
|
@@ -5290,6 +5308,7 @@ on_run_complete() {
|
|
|
5290
5308
|
if [ -n "$existing_pr" ]; then
|
|
5291
5309
|
_LOKI_DELEGATE_PR_URL="$existing_pr"
|
|
5292
5310
|
export _LOKI_DELEGATE_PR_URL
|
|
5311
|
+
_loki_persist_pr_url "$existing_pr"
|
|
5293
5312
|
log_info "LOKI_DELEGATE_PR=1: PR already exists for branch '$branch': $existing_pr (skipping create)."
|
|
5294
5313
|
return 0
|
|
5295
5314
|
fi
|
|
@@ -5321,6 +5340,7 @@ ${_del_receipt}"
|
|
|
5321
5340
|
# Export so build_completion_summary folds the url into the summary.
|
|
5322
5341
|
_LOKI_DELEGATE_PR_URL="$pr_url"
|
|
5323
5342
|
export _LOKI_DELEGATE_PR_URL
|
|
5343
|
+
_loki_persist_pr_url "$pr_url"
|
|
5324
5344
|
log_info "Pull request opened: $pr_url"
|
|
5325
5345
|
else
|
|
5326
5346
|
log_warn "LOKI_DELEGATE_PR=1: gh pr create did not return a URL (a PR may already exist for this branch)."
|
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:** v9.
|
|
5
|
+
**Version:** v9.48.2
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
package/loki-ts/dist/loki.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var _t=Object.create;var{getPrototypeOf:vt,defineProperty:jG,getOwnPropertyNames:ht}=Object;var gt=Object.prototype.hasOwnProperty;function mt($){return this[$]}var ut,dt,pt=($,X,Q)=>{var z=$!=null&&typeof $==="object";if(z){var Z=X?ut??=new WeakMap:dt??=new WeakMap,K=Z.get($);if(K)return K}Q=$!=null?_t(vt($)):{};let J=X||!$||!$.__esModule?jG(Q,"default",{value:$,enumerable:!0}):Q;for(let q of ht($))if(!gt.call(J,q))jG(J,q,{get:mt.bind($,q),enumerable:!0});if(z)Z.set($,J);return J};var zq=($,X)=>()=>(X||$((X={exports:{}}).exports,X),X.exports);var ct=($)=>$;function lt($,X){this[$]=ct.bind(null,X)}var B1=($,X)=>{for(var Q in X)jG($,Q,{get:X[Q],enumerable:!0,configurable:!0,set:lt.bind(X,Q)})};var s=($,X)=>()=>($&&(X=$($=0)),X);var w5=import.meta.require;var UR={};B1(UR,{lokiDir:()=>h0,homeLokiDir:()=>WQ,findRepoRootForVersion:()=>AG,REPO_ROOT:()=>L1});import{resolve as h2,dirname as LG}from"path";import{fileURLToPath as it}from"url";import{existsSync as Zq}from"fs";import{homedir as at}from"os";function ot(){let $=YR;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(YR,"..","..","..")}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 WQ(){return h2(at(),".loki")}var YR,L1;var k1=s(()=>{YR=LG(it(import.meta.url));L1=ot()});import{readFileSync as st}from"fs";import{resolve as nt,dirname as rt}from"path";import{fileURLToPath as tt}from"url";function j9(){if(n3!==null)return n3;let $="9.
|
|
2
|
+
var _t=Object.create;var{getPrototypeOf:vt,defineProperty:jG,getOwnPropertyNames:ht}=Object;var gt=Object.prototype.hasOwnProperty;function mt($){return this[$]}var ut,dt,pt=($,X,Q)=>{var z=$!=null&&typeof $==="object";if(z){var Z=X?ut??=new WeakMap:dt??=new WeakMap,K=Z.get($);if(K)return K}Q=$!=null?_t(vt($)):{};let J=X||!$||!$.__esModule?jG(Q,"default",{value:$,enumerable:!0}):Q;for(let q of ht($))if(!gt.call(J,q))jG(J,q,{get:mt.bind($,q),enumerable:!0});if(z)Z.set($,J);return J};var zq=($,X)=>()=>(X||$((X={exports:{}}).exports,X),X.exports);var ct=($)=>$;function lt($,X){this[$]=ct.bind(null,X)}var B1=($,X)=>{for(var Q in X)jG($,Q,{get:X[Q],enumerable:!0,configurable:!0,set:lt.bind(X,Q)})};var s=($,X)=>()=>($&&(X=$($=0)),X);var w5=import.meta.require;var UR={};B1(UR,{lokiDir:()=>h0,homeLokiDir:()=>WQ,findRepoRootForVersion:()=>AG,REPO_ROOT:()=>L1});import{resolve as h2,dirname as LG}from"path";import{fileURLToPath as it}from"url";import{existsSync as Zq}from"fs";import{homedir as at}from"os";function ot(){let $=YR;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(YR,"..","..","..")}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 WQ(){return h2(at(),".loki")}var YR,L1;var k1=s(()=>{YR=LG(it(import.meta.url));L1=ot()});import{readFileSync as st}from"fs";import{resolve as nt,dirname as rt}from"path";import{fileURLToPath as tt}from"url";function j9(){if(n3!==null)return n3;let $="9.48.2";if(typeof $==="string"&&$.length>0)return n3=$,n3;try{let X=rt(tt(import.meta.url)),Q=AG(X);n3=st(nt(Q,"VERSION"),"utf-8").trim()}catch{n3="unknown"}return n3}var n3=null;var Kq=s(()=>{k1()});var OR={};B1(OR,{runOrThrow:()=>Be,run:()=>$1,readStreamCapped:()=>Jq,commandVersion:()=>Me,commandExists:()=>g5,ShellError:()=>TG,MAX_STDOUT_BYTES:()=>MR});async function Jq($,X=MR){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 Be($,X={}){let Q=await $1($,X);if(Q.exitCode!==0)throw new TG(`command failed (${Q.exitCode}): ${$.join(" ")}`,Q.exitCode,Q.stdout,Q.stderr);return Q}async function g5($){let X=Ne($),Q=await $1(["sh","-c",`command -v ${X}`],{timeoutMs:5000});if(Q.exitCode===0)return Q.stdout.trim()||null;return null}function Ne($){if(!/^[A-Za-z0-9._/-]+$/.test($))throw Error(`refused to shell-escape suspect token: ${$}`);return $}async function Me($,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 MR=16777216,TG;var y8=s(()=>{TG=class TG 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 Oe?"":$}var Oe,p0,$5,q1,D61,A1,f1,m5,r;var t7=s(()=>{Oe=(process.env.NO_COLOR??"").length>0;p0=g2("\x1B[0;31m"),$5=g2("\x1B[0;32m"),q1=g2("\x1B[1;33m"),D61=g2("\x1B[0;34m"),A1=g2("\x1B[0;36m"),f1=g2("\x1B[1m"),m5=g2("\x1B[2m"),r=g2("\x1B[0m")});import{existsSync as we}from"fs";async function Z2(){if(GQ!==void 0)return GQ;let $="/opt/homebrew/bin/python3.12";if(we($))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 vR={};B1(vR,{runStatus:()=>te});import{existsSync as u5,readFileSync as C9,readdirSync as ER,statSync as xR}from"fs";import{resolve as A5,basename as pe}from"path";import{homedir as ce}from"os";function kR($){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 SR($,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=kR($),Y=kR(X);return` ${f1}${Q}${r} ${J}[${q}]${r} ${z}% (${V} / ${Y})`}async function ie(){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)
|
|
@@ -1337,4 +1337,4 @@ Set LOKI_LEGACY_BASH=1 to force the bash CLI for every command.
|
|
|
1337
1337
|
`),2}case"start":{let{runStart:z}=await Promise.resolve().then(() => (yt(),St));return z(Q)}default:return process.stderr.write(`Unknown command: ${X}
|
|
1338
1338
|
`),process.stderr.write(bt),2}}wR();process.on("SIGINT",()=>process.exit(130));process.on("SIGTERM",()=>process.exit(143));var K61=await Z61(Bun.argv.slice(2));process.exit(K61);
|
|
1339
1339
|
|
|
1340
|
-
//# debugId=
|
|
1340
|
+
//# debugId=5ED131B9EB93A5047CFCB3C8625CAE63
|
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.48.2",
|
|
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",
|
|
@@ -69,6 +69,8 @@
|
|
|
69
69
|
"tools/",
|
|
70
70
|
"plugins/",
|
|
71
71
|
".claude-plugin/marketplace.json",
|
|
72
|
+
".github/workflows/loki-issue-to-pr.yml",
|
|
73
|
+
".github/actions/issue-to-pr/",
|
|
72
74
|
"claude/hooks/",
|
|
73
75
|
"autonomy/",
|
|
74
76
|
"providers/",
|
|
@@ -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.48.2",
|
|
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",
|