loki-mode 8.65.0 → 8.67.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/loki +86 -0
- package/autonomy/provider-offer.sh +123 -0
- package/dashboard/__init__.py +1 -1
- package/loki-ts/dist/loki.js +342 -341
- package/mcp/__init__.py +1 -1
- package/package.json +1 -1
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
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 v8.
|
|
6
|
+
# Loki Mode v8.67.0
|
|
7
7
|
|
|
8
8
|
**You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
|
|
9
9
|
|
|
@@ -469,4 +469,4 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
|
|
|
469
469
|
|
|
470
470
|
---
|
|
471
471
|
|
|
472
|
-
**v8.
|
|
472
|
+
**v8.67.0 | [Autonomi](https://www.autonomi.dev/) flagship product | ~410 lines core**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
8.
|
|
1
|
+
8.67.0
|
package/autonomy/loki
CHANGED
|
@@ -2083,6 +2083,59 @@ cmd_start() {
|
|
|
2083
2083
|
esac
|
|
2084
2084
|
done
|
|
2085
2085
|
|
|
2086
|
+
# Explicit-provider pre-flight. Runs BEFORE provider_offer_gate below, and
|
|
2087
|
+
# is deliberately narrower than it.
|
|
2088
|
+
#
|
|
2089
|
+
# provider_offer_gate passes when ANY provider is on PATH, so `--provider
|
|
2090
|
+
# codex` on a claude-only machine sails through it and dies much later in
|
|
2091
|
+
# the runner. And when NOTHING is installed the gate offers to install
|
|
2092
|
+
# CLAUDE, which is a nudge toward substituting a provider the user did not
|
|
2093
|
+
# ask for. An explicit choice that cannot be honoured is an error, never a
|
|
2094
|
+
# silent (or suggested) swap: running a different model than the one asked
|
|
2095
|
+
# for is worse than failing.
|
|
2096
|
+
#
|
|
2097
|
+
# Only guards an EXPLICIT choice (--provider flag or LOKI_PROVIDER). The
|
|
2098
|
+
# default path returns immediately and still gets the friendly install
|
|
2099
|
+
# offer below. The later check at the "Pre-flight: check that the provider
|
|
2100
|
+
# CLI is installed" block stays: it covers effective_provider, which
|
|
2101
|
+
# includes the default, so the two have different scopes.
|
|
2102
|
+
local _pf_explicit="${provider:-${LOKI_PROVIDER:-}}"
|
|
2103
|
+
if [ -n "$_pf_explicit" ] && ! command -v "$_pf_explicit" >/dev/null 2>&1; then
|
|
2104
|
+
# Provider name == binary name here, same assumption as the existing
|
|
2105
|
+
# check below and provider-offer.sh:53. opencode is included; it is in
|
|
2106
|
+
# SUPPORTED_PROVIDERS but missing from the older lists.
|
|
2107
|
+
local _pf_installed=""
|
|
2108
|
+
local _pf_p
|
|
2109
|
+
for _pf_p in claude codex cline aider opencode; do
|
|
2110
|
+
if command -v "$_pf_p" >/dev/null 2>&1; then
|
|
2111
|
+
_pf_installed="${_pf_installed:+$_pf_installed }$_pf_p"
|
|
2112
|
+
fi
|
|
2113
|
+
done
|
|
2114
|
+
|
|
2115
|
+
echo -e "${RED}Error: you asked for provider '$_pf_explicit', but its CLI is not installed.${NC}" >&2
|
|
2116
|
+
echo "" >&2
|
|
2117
|
+
echo "Install it:" >&2
|
|
2118
|
+
case "$_pf_explicit" in
|
|
2119
|
+
claude) echo " npm install -g @anthropic-ai/claude-code" >&2 ;;
|
|
2120
|
+
codex) echo " npm install -g @openai/codex" >&2 ;;
|
|
2121
|
+
cline) echo " npm install -g cline" >&2 ;;
|
|
2122
|
+
aider) echo " pip install aider-chat" >&2 ;;
|
|
2123
|
+
opencode) echo " npm install -g opencode-ai" >&2 ;;
|
|
2124
|
+
*) echo " No install command is known for '$_pf_explicit'." >&2 ;;
|
|
2125
|
+
esac
|
|
2126
|
+
echo "" >&2
|
|
2127
|
+
if [ -n "$_pf_installed" ]; then
|
|
2128
|
+
echo "Installed providers on this machine: $_pf_installed" >&2
|
|
2129
|
+
echo "Re-run with one of those, e.g. loki start --provider ${_pf_installed%% *}" >&2
|
|
2130
|
+
else
|
|
2131
|
+
echo "No supported provider CLI is installed on this machine." >&2
|
|
2132
|
+
echo "Supported providers: claude, codex, cline, aider, opencode" >&2
|
|
2133
|
+
fi
|
|
2134
|
+
echo "" >&2
|
|
2135
|
+
echo "Loki will not silently run a different provider than the one you asked for." >&2
|
|
2136
|
+
exit 1
|
|
2137
|
+
fi
|
|
2138
|
+
|
|
2086
2139
|
# v7.29.0: provider pre-flight gate. If no provider CLI is installed, offer
|
|
2087
2140
|
# to install one (TTY) or print honest manual instructions and exit 2
|
|
2088
2141
|
# (non-TTY/CI), BEFORE any spend or runner entry. This moves what used to be
|
|
@@ -11229,6 +11282,18 @@ cmd_doctor() {
|
|
|
11229
11282
|
fi
|
|
11230
11283
|
echo ""
|
|
11231
11284
|
|
|
11285
|
+
# Provider Availability. Which provider a build would ACTUALLY pick, which
|
|
11286
|
+
# is decided by providers/loader.sh auto_detect_provider, not by PATH order
|
|
11287
|
+
# and not by the section above. Rendered by the shared helper in
|
|
11288
|
+
# provider-offer.sh so the Bun route prints the identical bytes (doctor
|
|
11289
|
+
# stdout is byte-compared -- tests/test-doctor-blocker-parity.sh). Skipped
|
|
11290
|
+
# silently, with no error, when loader.sh is missing or unsourceable.
|
|
11291
|
+
if declare -f render_provider_availability >/dev/null 2>&1; then
|
|
11292
|
+
if render_provider_availability; then
|
|
11293
|
+
echo ""
|
|
11294
|
+
fi
|
|
11295
|
+
fi
|
|
11296
|
+
|
|
11232
11297
|
echo -e "${CYAN}API Keys:${NC}"
|
|
11233
11298
|
# Note: CLI tools use their own login sessions outside Docker/K8s.
|
|
11234
11299
|
# This section helps first-time users verify they can authenticate.
|
|
@@ -11710,6 +11775,16 @@ else:
|
|
|
11710
11775
|
cmd_doctor_json() {
|
|
11711
11776
|
local _loki_version
|
|
11712
11777
|
_loki_version=$(get_version)
|
|
11778
|
+
# Provider availability, computed in bash and handed to the python program
|
|
11779
|
+
# as an env var (same pattern as LOKI_VERSION). Computed here rather than
|
|
11780
|
+
# inside the program because the answer comes from sourcing loader.sh.
|
|
11781
|
+
# Empty when loader.sh is unavailable, and the key is then null: the same
|
|
11782
|
+
# graceful skip the text section performs.
|
|
11783
|
+
local _provider_availability=""
|
|
11784
|
+
if declare -f provider_availability_json >/dev/null 2>&1; then
|
|
11785
|
+
_provider_availability="$(provider_availability_json 2>/dev/null || true)"
|
|
11786
|
+
fi
|
|
11787
|
+
LOKI_PROVIDER_AVAILABILITY="$_provider_availability" \
|
|
11713
11788
|
LOKI_VERSION="$_loki_version" \
|
|
11714
11789
|
LOKI_CATALOG_PATH="${LOKI_MODEL_CATALOG:-${_LOKI_SCRIPT_DIR}/../providers/model_catalog.json}" \
|
|
11715
11790
|
python3 -c "
|
|
@@ -11913,9 +11988,20 @@ except Exception:
|
|
|
11913
11988
|
model_catalog = {'status': 'warn', 'updated': None, 'age_days': None,
|
|
11914
11989
|
'detail': 'Catalog unreadable or missing an ISO \"updated\" date -- cannot determine age'}
|
|
11915
11990
|
|
|
11991
|
+
# Provider availability, handed in from bash (see cmd_doctor_json). Null when
|
|
11992
|
+
# providers/loader.sh could not be sourced, mirroring the text sections skip.
|
|
11993
|
+
# CAUTION: this block lives inside a DOUBLE-QUOTED python3 -c program, so no
|
|
11994
|
+
# apostrophes and no double quotes anywhere here, comments included.
|
|
11995
|
+
try:
|
|
11996
|
+
_pa_raw = os.environ.get('LOKI_PROVIDER_AVAILABILITY', '').strip()
|
|
11997
|
+
provider_availability = json.loads(_pa_raw) if _pa_raw else None
|
|
11998
|
+
except Exception:
|
|
11999
|
+
provider_availability = None
|
|
12000
|
+
|
|
11916
12001
|
result = {
|
|
11917
12002
|
'loki_mode_version': os.environ.get('LOKI_VERSION', 'unknown'),
|
|
11918
12003
|
'checks': checks,
|
|
12004
|
+
'provider_availability': provider_availability,
|
|
11919
12005
|
'disk': {
|
|
11920
12006
|
'available_gb': disk_gb,
|
|
11921
12007
|
'status': disk_status
|
|
@@ -35,6 +35,22 @@ else
|
|
|
35
35
|
_PO_NC=$'\033[0m'
|
|
36
36
|
fi
|
|
37
37
|
|
|
38
|
+
# Section colors for render_provider_availability. Deliberately gated on
|
|
39
|
+
# NO_COLOR ALONE, unlike the _PO_* set above which also blanks on a non-TTY.
|
|
40
|
+
# The section is printed inside `loki doctor` next to blocks colored by loki own
|
|
41
|
+
# CYAN/GREEN/NC, and those are blanked on NO_COLOR only (autonomy/loki:37). A
|
|
42
|
+
# TTY test here would strip color from this one section whenever doctor stdout
|
|
43
|
+
# is piped while every neighbour kept its escapes.
|
|
44
|
+
if [ -n "${NO_COLOR:-}" ]; then
|
|
45
|
+
_PO_S_CYAN=''; _PO_S_GREEN=''; _PO_S_YELLOW=''; _PO_S_DIM=''; _PO_S_NC=''
|
|
46
|
+
else
|
|
47
|
+
_PO_S_CYAN=$'\033[0;36m'
|
|
48
|
+
_PO_S_GREEN=$'\033[0;32m'
|
|
49
|
+
_PO_S_YELLOW=$'\033[1;33m'
|
|
50
|
+
_PO_S_DIM=$'\033[2m'
|
|
51
|
+
_PO_S_NC=$'\033[0m'
|
|
52
|
+
fi
|
|
53
|
+
|
|
38
54
|
# The one canonical install command. Quoted everywhere; never re-derived.
|
|
39
55
|
_PO_INSTALL_CMD="npm install -g @anthropic-ai/claude-code"
|
|
40
56
|
|
|
@@ -351,6 +367,109 @@ provider_offer_gate() {
|
|
|
351
367
|
return 2
|
|
352
368
|
}
|
|
353
369
|
|
|
370
|
+
# render_provider_availability: print the "Provider Availability" doctor section.
|
|
371
|
+
#
|
|
372
|
+
# WHY IT LIVES HERE. `loki doctor` stdout is compared byte for byte between the
|
|
373
|
+
# bash route and the Bun route (tests/test-doctor-blocker-parity.sh, and the
|
|
374
|
+
# bun-parity workflow). Two independent renderers drift; one shared renderer
|
|
375
|
+
# cannot. This is the same parity-by-construction seam the install offer and the
|
|
376
|
+
# detect-sdk probe already use, so doctor.ts calls this instead of reimplementing
|
|
377
|
+
# the priority list in TypeScript.
|
|
378
|
+
#
|
|
379
|
+
# WHY IT DOES NOT REUSE THE EXISTING "AI Providers" BLOCK. That block answers a
|
|
380
|
+
# different question -- is each CLI on PATH, and how do I install it. This one
|
|
381
|
+
# answers "which provider would a build actually pick", which is a property of
|
|
382
|
+
# providers/loader.sh auto_detect_provider, not of PATH. It also covers opencode,
|
|
383
|
+
# which the older block never listed.
|
|
384
|
+
#
|
|
385
|
+
# THE ORDER IS NOT SUPPORTED_PROVIDERS. auto_detect_provider walks
|
|
386
|
+
# claude cline codex aider opencode; SUPPORTED_PROVIDERS is declared
|
|
387
|
+
# claude codex cline aider opencode -- codex and cline are SWAPPED. Marking the
|
|
388
|
+
# first installed entry of SUPPORTED_PROVIDERS would name codex on a machine
|
|
389
|
+
# where a build would really pick cline. So the selected provider is always
|
|
390
|
+
# whatever auto_detect_provider returns, never re-derived here.
|
|
391
|
+
#
|
|
392
|
+
# DEGRADES SILENTLY. Requirement: if loader.sh cannot be sourced, the section is
|
|
393
|
+
# skipped rather than erroring. Everything runs inside one subshell, so a missing
|
|
394
|
+
# or broken loader returns non-zero with nothing printed and doctor continues.
|
|
395
|
+
render_provider_availability() {
|
|
396
|
+
# Path derived from THIS FILE, never from SKILL_DIR or _LOKI_SCRIPT_DIR:
|
|
397
|
+
# those belong to autonomy/loki and are unset when doctor.ts spawns this
|
|
398
|
+
# script standalone, which would blank the section on the Bun route only.
|
|
399
|
+
local _po_here
|
|
400
|
+
_po_here="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." 2>/dev/null && pwd)" || return 1
|
|
401
|
+
local _loader="$_po_here/providers/loader.sh"
|
|
402
|
+
[ -f "$_loader" ] || return 1
|
|
403
|
+
|
|
404
|
+
(
|
|
405
|
+
# shellcheck source=/dev/null
|
|
406
|
+
source "$_loader" >/dev/null 2>&1 || exit 1
|
|
407
|
+
declare -f auto_detect_provider >/dev/null 2>&1 || exit 1
|
|
408
|
+
[ "${#SUPPORTED_PROVIDERS[@]}" -gt 0 ] 2>/dev/null || exit 1
|
|
409
|
+
|
|
410
|
+
local _selected
|
|
411
|
+
_selected="$(auto_detect_provider 2>/dev/null)"
|
|
412
|
+
|
|
413
|
+
printf '%s\n' "${_PO_S_CYAN}Provider Availability:${_PO_S_NC}"
|
|
414
|
+
local _p
|
|
415
|
+
for _p in "${SUPPORTED_PROVIDERS[@]}"; do
|
|
416
|
+
if check_provider_installed "$_p" >/dev/null 2>&1; then
|
|
417
|
+
if [ "$_p" = "$_selected" ]; then
|
|
418
|
+
printf '%s\n' " ${_PO_S_GREEN}PASS${_PO_S_NC} $_p - installed ${_PO_S_DIM}(auto-selected)${_PO_S_NC}"
|
|
419
|
+
else
|
|
420
|
+
printf '%s\n' " ${_PO_S_GREEN}PASS${_PO_S_NC} $_p - installed"
|
|
421
|
+
fi
|
|
422
|
+
else
|
|
423
|
+
printf '%s\n' " ${_PO_S_YELLOW}WARN${_PO_S_NC} $_p - not installed"
|
|
424
|
+
fi
|
|
425
|
+
done
|
|
426
|
+
|
|
427
|
+
if [ -n "$_selected" ]; then
|
|
428
|
+
printf '%s\n' " ${_PO_S_DIM}Auto-selected provider: ${_selected} (override with LOKI_PROVIDER)${_PO_S_NC}"
|
|
429
|
+
else
|
|
430
|
+
printf '%s\n' " ${_PO_S_DIM}Auto-selected provider: none (no supported CLI installed)${_PO_S_NC}"
|
|
431
|
+
fi
|
|
432
|
+
) || return 1
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
# provider_availability_json: the same data as one JSON object, for doctor --json.
|
|
436
|
+
# Separate from the renderer so neither format has to parse the other. Same
|
|
437
|
+
# degrade rule: no loader means no output and a non-zero status.
|
|
438
|
+
provider_availability_json() {
|
|
439
|
+
local _po_here
|
|
440
|
+
_po_here="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." 2>/dev/null && pwd)" || return 1
|
|
441
|
+
local _loader="$_po_here/providers/loader.sh"
|
|
442
|
+
[ -f "$_loader" ] || return 1
|
|
443
|
+
|
|
444
|
+
(
|
|
445
|
+
# shellcheck source=/dev/null
|
|
446
|
+
source "$_loader" >/dev/null 2>&1 || exit 1
|
|
447
|
+
declare -f auto_detect_provider >/dev/null 2>&1 || exit 1
|
|
448
|
+
[ "${#SUPPORTED_PROVIDERS[@]}" -gt 0 ] 2>/dev/null || exit 1
|
|
449
|
+
|
|
450
|
+
local _selected _p _rows=""
|
|
451
|
+
_selected="$(auto_detect_provider 2>/dev/null)"
|
|
452
|
+
for _p in "${SUPPORTED_PROVIDERS[@]}"; do
|
|
453
|
+
if check_provider_installed "$_p" >/dev/null 2>&1; then
|
|
454
|
+
_rows="${_rows}${_p}=true"$'\n'
|
|
455
|
+
else
|
|
456
|
+
_rows="${_rows}${_p}=false"$'\n'
|
|
457
|
+
fi
|
|
458
|
+
done
|
|
459
|
+
_PA_SELECTED="$_selected" _PA_ROWS="$_rows" python3 -c '
|
|
460
|
+
import json, os
|
|
461
|
+
rows = []
|
|
462
|
+
for line in os.environ.get("_PA_ROWS", "").splitlines():
|
|
463
|
+
if not line:
|
|
464
|
+
continue
|
|
465
|
+
name, _, installed = line.partition("=")
|
|
466
|
+
rows.append({"name": name, "installed": installed == "true"})
|
|
467
|
+
selected = os.environ.get("_PA_SELECTED", "") or None
|
|
468
|
+
print(json.dumps({"selected": selected, "providers": rows}, indent=2))
|
|
469
|
+
' 2>/dev/null || exit 1
|
|
470
|
+
) || return 1
|
|
471
|
+
}
|
|
472
|
+
|
|
354
473
|
# Executed directly (doctor.ts child_process bridge, or manual): run the offer.
|
|
355
474
|
# When sourced by autonomy/loki, this block does not run.
|
|
356
475
|
if [ "${BASH_SOURCE[0]}" = "$0" ]; then
|
|
@@ -362,6 +481,10 @@ if [ "${BASH_SOURCE[0]}" = "$0" ]; then
|
|
|
362
481
|
# (loki-ts/src/commands/doctor.ts). Prints nothing, so it cannot perturb
|
|
363
482
|
# the parity-captured stdout.
|
|
364
483
|
detect-sdk) detect_bundled_sdk_provider ;;
|
|
484
|
+
# Doctor "Provider Availability" section + its --json payload. Both
|
|
485
|
+
# routes call these so the two renderings cannot drift apart.
|
|
486
|
+
providers) render_provider_availability ;;
|
|
487
|
+
providers-json) provider_availability_json ;;
|
|
365
488
|
*) offer_provider_install report ;;
|
|
366
489
|
esac
|
|
367
490
|
fi
|