loki-mode 11.4.2 → 11.5.1
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/chat.sh +6 -3
- package/autonomy/lib/engine10-push.sh +19 -1
- package/autonomy/lib/help-core.sh +1 -1
- package/autonomy/lib/proof-generator.py +23 -5
- package/autonomy/lib/proof-verify.py +607 -5
- package/autonomy/lib/run-summary.sh +17 -1
- package/autonomy/lib/setup-requirements.json +35 -0
- package/autonomy/loki +232 -36
- package/autonomy/provider-offer.sh +95 -47
- package/autonomy/route.sh +38 -6
- package/autonomy/run.sh +42 -14
- package/autonomy/setup-wizard.sh +19 -10
- package/autonomy/verify.sh +40 -1
- package/completions/_loki +3 -1
- package/completions/loki.bash +9 -3
- package/dashboard/__init__.py +1 -1
- package/docs/CLI-REFERENCE.md +3 -1
- package/docs/EVALUATING.md +27 -0
- package/docs/HARNESS-INTELLIGENCE-PLAN.md +20 -0
- package/docs/INSTALLATION.md +1 -1
- package/docs/KNOWN-ISSUES.md +10 -1
- package/docs/PROOF-PASSPORT.md +114 -0
- package/docs/alternative-installations.md +103 -0
- package/docs/cost-controls.md +139 -0
- package/docs/environment-variables.md +36 -0
- package/docs/exit-codes.md +102 -2
- package/docs/spec-first-intent.md +29 -0
- package/docs/v10/CLI-MODERN.md +2 -2
- package/docs/v10/ENGINE.md +32 -0
- package/loki-ts/data/model-pricing.json +1 -0
- package/loki-ts/dist/loki.js +1095 -1043
- package/mcp/__init__.py +1 -1
- package/package.json +2 -2
- package/packages/control-plane/dist/server.js +1721 -707
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/plugins/loki-mode/README.md +41 -1
- package/plugins/loki-mode/commands/handoff.md +12 -0
- package/plugins/loki-mode/commands/loki-verify.md +9 -2
- package/plugins/loki-mode/commands/start.md +20 -0
- package/plugins/loki-mode/hooks/hooks.json +11 -0
- package/plugins/loki-mode/scripts/loki-stop-verify.sh +84 -0
- package/web-app/dist/assets/{AdminPage-CYJ2BWRC.js → AdminPage-Cbu3pXL8.js} +1 -1
- package/web-app/dist/assets/{Avatar-DdK4wynI.js → Avatar-DGqGGcGx.js} +1 -1
- package/web-app/dist/assets/{Badge-CrX3MI7J.js → Badge-Bhlipt6v.js} +1 -1
- package/web-app/dist/assets/{Button-709-wwGM.js → Button-CpN2sO61.js} +1 -1
- package/web-app/dist/assets/{CockpitPage-BapdTInO.js → CockpitPage-BqeDJwdL.js} +1 -1
- package/web-app/dist/assets/{ComparePage-DT99pGvA.js → ComparePage-DUieA2ba.js} +1 -1
- package/web-app/dist/assets/{ErrorBoundary-B0uJSys8.js → ErrorBoundary-DTWsYrOm.js} +1 -1
- package/web-app/dist/assets/{EvidenceReceiptPanel-BtMFgElP.js → EvidenceReceiptPanel-BU_B9X19.js} +1 -1
- package/web-app/dist/assets/{GitHubIssuesPanel-DjJuU941.js → GitHubIssuesPanel-DEZoLOsP.js} +1 -1
- package/web-app/dist/assets/{GitHubPRsPanel-HXfEX1BC.js → GitHubPRsPanel-BEsnrq7Y.js} +1 -1
- package/web-app/dist/assets/{HomePage-Cqyves-S.js → HomePage-BoUVuq7h.js} +2 -2
- package/web-app/dist/assets/{LoginPage-jUbtC7_Y.js → LoginPage-CmOED7vb.js} +1 -1
- package/web-app/dist/assets/{MagicPage-DHRsqjgR.js → MagicPage-DATZitrZ.js} +1 -1
- package/web-app/dist/assets/{MetricsPage-B-pED05R.js → MetricsPage-DGL1v0I-.js} +1 -1
- package/web-app/dist/assets/{NotFoundPage-CsbUs21R.js → NotFoundPage-C2WgOjZd.js} +1 -1
- package/web-app/dist/assets/{ProjectPage-BtlLEQwB.js → ProjectPage-BMi1tepj.js} +3 -3
- package/web-app/dist/assets/{ProjectsPage-DaRbRjSp.js → ProjectsPage-vc3y5YPh.js} +1 -1
- package/web-app/dist/assets/{SettingsPage-DALrtP3F.js → SettingsPage-kbq0Ftvi.js} +1 -1
- package/web-app/dist/assets/{ShowcasePage-CoPHSNP0.js → ShowcasePage-Bn6Q8Kbg.js} +1 -1
- package/web-app/dist/assets/{SystemSettingsPage-kOuSN50O.js → SystemSettingsPage-Basmhs_b.js} +1 -1
- package/web-app/dist/assets/{TeamsPage-DGWK0LMp.js → TeamsPage-BTqOc4TR.js} +1 -1
- package/web-app/dist/assets/{TemplatesPage-C-_10CwA.js → TemplatesPage-2P9002VL.js} +1 -1
- package/web-app/dist/assets/{TerminalOutput-Cz_vPbXL.js → TerminalOutput-CAoSPBrg.js} +1 -1
- package/web-app/dist/assets/{activity-icIsXJVa.js → activity-BcWVWCqU.js} +1 -1
- package/web-app/dist/assets/{bell-DbPR2_4r.js → bell-CYRqqgZ6.js} +1 -1
- package/web-app/dist/assets/{bot-DvjP3Yh5.js → bot-CU7gdn3g.js} +1 -1
- package/web-app/dist/assets/{check-D1OBxHeU.js → check-DLlCpz9V.js} +1 -1
- package/web-app/dist/assets/{chevron-left-D09jDZ29.js → chevron-left-CE9Cb30C.js} +1 -1
- package/web-app/dist/assets/{circle-alert-DyZMLOcC.js → circle-alert-uou4bjua.js} +1 -1
- package/web-app/dist/assets/{clock-CdpdJTId.js → clock-C_dSJcDX.js} +1 -1
- package/web-app/dist/assets/{cloud-CoLTlmoj.js → cloud-DZ22ITF6.js} +1 -1
- package/web-app/dist/assets/{code-xml-DrkE2ZZY.js → code-xml-BrJS0hhS.js} +1 -1
- package/web-app/dist/assets/{database-CMQQuM2R.js → database-D2HOmxtl.js} +1 -1
- package/web-app/dist/assets/{dollar-sign-CuioDaOG.js → dollar-sign-CQ1vK_6q.js} +1 -1
- package/web-app/dist/assets/{file-code-corner-Cx9j9K1S.js → file-code-corner-w2vpGm5d.js} +1 -1
- package/web-app/dist/assets/{file-plus-CYD2zaaI.js → file-plus-DlF6wjkD.js} +1 -1
- package/web-app/dist/assets/{globe-6w-hnQkL.js → globe-Dy3lBJg1.js} +1 -1
- package/web-app/dist/assets/{hammer-BpqtautL.js → hammer-C3xIiRXN.js} +1 -1
- package/web-app/dist/assets/{index-Dzs-9EgJ.js → index-4t-_IW2y.js} +3 -3
- package/web-app/dist/assets/{layers-D5hd7jb7.js → layers-Y8Fs8qXI.js} +1 -1
- package/web-app/dist/assets/{loader-circle-C6Y9x_7H.js → loader-circle-CxgN1v4m.js} +1 -1
- package/web-app/dist/assets/{lock-D51L7rYh.js → lock-DFFNbXDs.js} +1 -1
- package/web-app/dist/assets/{package-BJF8hkP8.js → package-5e6qCTUg.js} +1 -1
- package/web-app/dist/assets/{plus-D5kUQ79n.js → plus-C0Go_ytj.js} +1 -1
- package/web-app/dist/assets/{refresh-cw-BKdlCa7F.js → refresh-cw-D4i-NW3o.js} +1 -1
- package/web-app/dist/assets/{rotate-ccw-_bd_YI1e.js → rotate-ccw-YlKkiUW6.js} +1 -1
- package/web-app/dist/assets/{scroll-text-DbkegIxF.js → scroll-text-4qXOHTap.js} +1 -1
- package/web-app/dist/assets/{server-DAwqFIsq.js → server-BB6zXNp9.js} +1 -1
- package/web-app/dist/assets/{shield-alert-BuR1tPHu.js → shield-alert-D4tzjB1H.js} +1 -1
- package/web-app/dist/assets/{thumbs-up-BF6p3mRd.js → thumbs-up-DZiRwdFj.js} +1 -1
- package/web-app/dist/assets/{trash-2-BVpnkqqz.js → trash-2-Dv_LkRIK.js} +1 -1
- package/web-app/dist/assets/{trending-down-DpsDvRwW.js → trending-down-BJYp9PQe.js} +1 -1
- package/web-app/dist/assets/{trending-up-mFogTjt3.js → trending-up-BTcXLklK.js} +1 -1
- package/web-app/dist/assets/{upload-4T8zpBsi.js → upload-fcHqwOxr.js} +1 -1
- package/web-app/dist/assets/{usePolling-DPXQv8WO.js → usePolling-BeJYw_4L.js} +1 -1
- package/web-app/dist/assets/{user-BYGIFaTm.js → user-BcDwUCsO.js} +1 -1
- package/web-app/dist/index.html +1 -1
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"comment": "Single source of truth for Loki setup requirements per execution path. Read by loki-ts/src/commands/doctor.ts (doctor, runtime errors), autonomy/provider-offer.sh (bash fallback), autonomy/setup-wizard.sh (loki setup) and tests (the generated block in docs/alternative-installations.md is asserted against it). Edit here, then run UPDATE_CONTRACT=1 bun test tests/commands/doctor.test.ts from loki-ts.",
|
|
4
|
+
"paths": [
|
|
5
|
+
{ "id": "common", "title": "All paths", "summary": "Needed by every Loki command" },
|
|
6
|
+
{ "id": "claude-cli", "title": "Claude Code CLI path (default, loki start)", "summary": "Loki drives the claude binary you installed and logged in" },
|
|
7
|
+
{ "id": "api-key-sdk", "title": "Anthropic API-key path (Agent SDK, no claude CLI)", "summary": "Opt-in with LOKI_SDK_MODE=full; the bundled Agent SDK runs the loop over HTTPS" },
|
|
8
|
+
{ "id": "other-providers", "title": "Other provider CLIs", "summary": "codex (degraded), cline, aider, opencode: any one replaces the claude CLI" }
|
|
9
|
+
],
|
|
10
|
+
"requirements": [
|
|
11
|
+
{ "id": "node", "path": "common", "level": "required", "kind": "command", "target": "node", "min": "20.0", "label": "Node.js 20 or newer", "fix": "install Node 20+ from https://nodejs.org" },
|
|
12
|
+
{ "id": "python3", "path": "common", "level": "required", "kind": "command", "target": "python3", "min": "3.8", "label": "Python 3.8 or newer", "fix": "install python3 with your package manager (brew install python3)" },
|
|
13
|
+
{ "id": "jq", "path": "common", "level": "required", "kind": "command", "target": "jq", "label": "jq", "fix": "install jq with your package manager (brew install jq)" },
|
|
14
|
+
{ "id": "git", "path": "common", "level": "required", "kind": "command", "target": "git", "label": "git", "fix": "install git with your package manager (brew install git)" },
|
|
15
|
+
{ "id": "curl", "path": "common", "level": "required", "kind": "command", "target": "curl", "label": "curl", "fix": "install curl with your package manager (brew install curl)" },
|
|
16
|
+
{ "id": "bash", "path": "common", "level": "optional", "kind": "command", "target": "bash", "min": "4.0", "label": "bash 4.0 or newer", "fix": "install a newer bash (brew install bash); macOS ships 3.2" },
|
|
17
|
+
{ "id": "bun", "path": "common", "level": "optional", "kind": "command", "target": "bun", "min": "1.3", "label": "Bun 1.3 or newer (bundled by npm install)", "fix": "reinstall without --no-optional (npm bundles @oven/bun-*) or install from https://bun.sh; without it loki falls back to the slower bash CLI" },
|
|
18
|
+
|
|
19
|
+
{ "id": "claude", "path": "claude-cli", "level": "required", "kind": "command", "target": "claude", "label": "claude CLI on PATH (then log in: claude auth login)", "fix": "npm install -g @anthropic-ai/claude-code" },
|
|
20
|
+
|
|
21
|
+
{ "id": "sdk-mode", "path": "api-key-sdk", "level": "required", "kind": "env_value", "target": ["LOKI_SDK_LOOP"], "values": ["1", "true"], "label": "SDK loop enabled (LOKI_SDK_MODE=full)", "fix": "export LOKI_SDK_MODE=full" },
|
|
22
|
+
{ "id": "sdk-credentials", "path": "api-key-sdk", "level": "required", "kind": "env_any", "target": ["ANTHROPIC_API_KEY", "ANTHROPIC_AUTH_TOKEN", "ANTHROPIC_BASE_URL"], "label": "Anthropic credentials (API key, auth token or gateway URL)", "fix": "export ANTHROPIC_API_KEY=<your key>" },
|
|
23
|
+
{ "id": "sdk-binary", "path": "api-key-sdk", "level": "required", "kind": "sdk_binary", "target": "@anthropic-ai/claude-agent-sdk", "label": "Claude Agent SDK platform binary (optional npm dependency)", "fix": "reinstall without --no-optional: npm install -g loki-mode (the SDK is an optionalDependency)" },
|
|
24
|
+
{ "id": "sdk-bun", "path": "api-key-sdk", "level": "required", "kind": "command", "target": "bun", "min": "1.3", "label": "Bun runtime (the SDK loop runs only on the Bun route)", "fix": "reinstall without --no-optional (npm bundles @oven/bun-*) or install from https://bun.sh" },
|
|
25
|
+
|
|
26
|
+
{ "id": "codex", "path": "other-providers", "level": "optional", "kind": "command", "target": "codex", "label": "codex CLI", "fix": "npm install -g @openai/codex" },
|
|
27
|
+
{ "id": "cline", "path": "other-providers", "level": "optional", "kind": "command", "target": "cline", "label": "cline CLI", "fix": "npm install -g cline" },
|
|
28
|
+
{ "id": "aider", "path": "other-providers", "level": "optional", "kind": "command", "target": "aider", "label": "aider CLI", "fix": "pip install aider-chat" },
|
|
29
|
+
{ "id": "opencode", "path": "other-providers", "level": "optional", "kind": "command", "target": "opencode", "label": "opencode CLI", "fix": "npm install -g opencode-ai" }
|
|
30
|
+
],
|
|
31
|
+
"missing_optional": [
|
|
32
|
+
{ "dependency": "@anthropic-ai/claude-agent-sdk (or its platform binary)", "effect": "The api-key-sdk path is unavailable and doctor reports it not ready. The claude-cli path and all other providers are unaffected." },
|
|
33
|
+
{ "dependency": "@oven/bun-* (Bun)", "effect": "bin/loki falls back to the bash CLI (slower). The api-key-sdk path is unavailable because the SDK loop runs only on Bun." }
|
|
34
|
+
]
|
|
35
|
+
}
|
package/autonomy/loki
CHANGED
|
@@ -71,6 +71,15 @@ if [ -f "$_LOKI_SCRIPT_DIR/lib/lock.sh" ]; then
|
|
|
71
71
|
source "$_LOKI_SCRIPT_DIR/lib/lock.sh"
|
|
72
72
|
fi
|
|
73
73
|
|
|
74
|
+
# Default per-run spend cap (single source: default_max_cost_usd in loki-ts/data/model-pricing.json,
|
|
75
|
+
# also read by loki-ts/src/e10ext/budget_cap.ts and autonomy/run.sh). Prints a plain number; 100 only if the file is unreadable.
|
|
76
|
+
loki_budget_default_usd() {
|
|
77
|
+
local v=""
|
|
78
|
+
[ -f "$_LOKI_SCRIPT_DIR/../loki-ts/data/model-pricing.json" ] && \
|
|
79
|
+
v="$(sed -n 's/.*"default_max_cost_usd"[[:space:]]*:[[:space:]]*\([0-9][0-9.]*\).*/\1/p' "$_LOKI_SCRIPT_DIR/../loki-ts/data/model-pricing.json" | head -1)"
|
|
80
|
+
printf '%s\n' "${v:-100}"
|
|
81
|
+
}
|
|
82
|
+
|
|
74
83
|
# Guarded browser opener (loki_open_url). Every browser open goes through it
|
|
75
84
|
# so tests, CI and non-TTY runs never pop a tab. If missing, nothing opens.
|
|
76
85
|
if [ -f "$_LOKI_SCRIPT_DIR/lib/browser-open.sh" ]; then
|
|
@@ -1838,7 +1847,7 @@ show_help_all() {
|
|
|
1838
1847
|
echo " --spec FILE Run against an edited spec (written by 'loki plan <task> --spec'; see also --spec-first)"
|
|
1839
1848
|
echo " --fresh-prd Regenerate the PRD from the codebase (no-PRD runs; ignores the reusable generated PRD)"
|
|
1840
1849
|
echo " --compliance PRESET Enable compliance mode (default|healthcare|fintech|government)"
|
|
1841
|
-
echo " --budget USD
|
|
1850
|
+
echo " --budget USD Per-run cost cap in USD (default $(loki_budget_default_usd); auto-pause when exceeded; see docs/cost-controls.md)"
|
|
1842
1851
|
echo " --bmad-project PATH Use BMAD Method project artifacts as input"
|
|
1843
1852
|
echo " --openspec PATH Use OpenSpec change directory as input"
|
|
1844
1853
|
echo " --config PATH Load settings from a config file (.yaml/.json/.env). Alias: --env-file, --vars"
|
|
@@ -2608,7 +2617,7 @@ cmd_start() {
|
|
|
2608
2617
|
echo " (ignores the reusable generated PRD; aliases: --regen-prd,"
|
|
2609
2618
|
echo " --regenerate-prd, --regen, or LOKI_PRD_REGEN=1)"
|
|
2610
2619
|
echo " --compliance PRESET Enable compliance mode (default|healthcare|fintech|government)"
|
|
2611
|
-
echo " --budget USD
|
|
2620
|
+
echo " --budget USD Per-run cost cap (default $(loki_budget_default_usd); auto-pause when exceeded)"
|
|
2612
2621
|
echo " --bmad-project PATH Use BMAD Method project artifacts as input"
|
|
2613
2622
|
echo " --openspec PATH Use OpenSpec change directory as input"
|
|
2614
2623
|
echo " --mirofish [URL] Enable MiroFish market validation (default: localhost:5001)"
|
|
@@ -2651,7 +2660,7 @@ cmd_start() {
|
|
|
2651
2660
|
echo " LOKI_AUTO_CONFIRM Set to 'true'/'false' to control prompts (takes precedence over CI)"
|
|
2652
2661
|
echo " CI Fallback: auto-confirms when 'true' and LOKI_AUTO_CONFIRM is unset"
|
|
2653
2662
|
echo " LOKI_MAX_ITERATIONS Max iteration count"
|
|
2654
|
-
echo " LOKI_BUDGET_LIMIT Cost
|
|
2663
|
+
echo " LOKI_BUDGET_LIMIT Cost cap in USD (default $(loki_budget_default_usd); empty means unlimited)"
|
|
2655
2664
|
echo ""
|
|
2656
2665
|
echo "Examples:"
|
|
2657
2666
|
echo " loki start # Interactive, analyze current dir"
|
|
@@ -3049,7 +3058,7 @@ cmd_start() {
|
|
|
3049
3058
|
echo -e "${RED}--budget must be greater than 0 (a 0 budget pauses before any work)${NC}" >&2
|
|
3050
3059
|
exit 1
|
|
3051
3060
|
fi
|
|
3052
|
-
export LOKI_BUDGET_LIMIT="$2"
|
|
3061
|
+
export LOKI_BUDGET_LIMIT="$2" LOKI_BUDGET_SOURCE=flag
|
|
3053
3062
|
shift 2
|
|
3054
3063
|
else
|
|
3055
3064
|
echo -e "${RED}--budget requires a USD amount (e.g., --budget 5.00)${NC}"
|
|
@@ -3067,7 +3076,7 @@ cmd_start() {
|
|
|
3067
3076
|
echo -e "${RED}--budget must be greater than 0 (a 0 budget pauses before any work)${NC}" >&2
|
|
3068
3077
|
exit 1
|
|
3069
3078
|
fi
|
|
3070
|
-
export LOKI_BUDGET_LIMIT="$budget_val"
|
|
3079
|
+
export LOKI_BUDGET_LIMIT="$budget_val" LOKI_BUDGET_SOURCE=flag
|
|
3071
3080
|
shift
|
|
3072
3081
|
;;
|
|
3073
3082
|
# v6.84.0: explicit mode flags (override auto-detection)
|
|
@@ -3956,15 +3965,8 @@ cmd_start() {
|
|
|
3956
3965
|
if ! command -v "$effective_provider" &>/dev/null; then
|
|
3957
3966
|
echo -e "${RED}Error: Provider CLI '$effective_provider' is not installed.${NC}"
|
|
3958
3967
|
echo ""
|
|
3959
|
-
echo "Install it first:"
|
|
3960
|
-
|
|
3961
|
-
claude) echo " npm install -g @anthropic-ai/claude-code" ;;
|
|
3962
|
-
codex) echo " npm install -g @openai/codex" ;;
|
|
3963
|
-
cline) echo " npm install -g cline" ;;
|
|
3964
|
-
aider) echo " pip install aider-chat" ;;
|
|
3965
|
-
opencode) echo " npm install -g opencode-ai" ;;
|
|
3966
|
-
*) echo " Check the provider documentation for installation." ;;
|
|
3967
|
-
esac
|
|
3968
|
+
echo "Install it first (same fix as loki doctor):"
|
|
3969
|
+
_loki_req_fix_line "$effective_provider"
|
|
3968
3970
|
echo ""
|
|
3969
3971
|
echo "Check your environment: loki doctor"
|
|
3970
3972
|
exit 1
|
|
@@ -5170,6 +5172,17 @@ cmd_resume() {
|
|
|
5170
5172
|
exit 0
|
|
5171
5173
|
fi
|
|
5172
5174
|
|
|
5175
|
+
# RECOVERY: an interrupted engine10 run is resumed at its phase by loki-ts/src/util/run_outputs.ts
|
|
5176
|
+
# (exit 0 resumed, 4 phase reported, 5 publish failed, anything else: nothing for it, fall through).
|
|
5177
|
+
if ls "$LOKI_DIR"/runs/e10-*/events.jsonl >/dev/null 2>&1; then
|
|
5178
|
+
local _e10_rc=0
|
|
5179
|
+
( _loki_bun_delegate engine10 resume "$@" ) || _e10_rc=$?
|
|
5180
|
+
case "$_e10_rc" in
|
|
5181
|
+
0 | 4) return 0 ;;
|
|
5182
|
+
5) return 1 ;;
|
|
5183
|
+
esac
|
|
5184
|
+
fi
|
|
5185
|
+
|
|
5173
5186
|
# Check if there is anything to resume before touching signal files
|
|
5174
5187
|
local has_pause_signal=false
|
|
5175
5188
|
local has_stop_signal=false
|
|
@@ -7119,8 +7132,14 @@ cmd_provider() {
|
|
|
7119
7132
|
cmd_provider_list
|
|
7120
7133
|
;;
|
|
7121
7134
|
info)
|
|
7135
|
+
case " $* " in
|
|
7136
|
+
*" --json "*) _loki_bun_delegate provider info "$@" || { echo "loki provider info --json needs bun: ${_LOKI_DELEGATE_WHY}" >&2; return 1; } ;;
|
|
7137
|
+
esac
|
|
7122
7138
|
cmd_provider_info "$@"
|
|
7123
7139
|
;;
|
|
7140
|
+
matrix)
|
|
7141
|
+
_loki_bun_delegate provider matrix "$@" || { echo "loki provider matrix needs bun: ${_LOKI_DELEGATE_WHY}" >&2; return 1; }
|
|
7142
|
+
;;
|
|
7124
7143
|
models)
|
|
7125
7144
|
cmd_provider_models
|
|
7126
7145
|
;;
|
|
@@ -7133,7 +7152,8 @@ cmd_provider() {
|
|
|
7133
7152
|
echo " show Show current provider (default)"
|
|
7134
7153
|
echo " set Set provider for this project"
|
|
7135
7154
|
echo " list List available providers"
|
|
7136
|
-
echo " info Show provider details"
|
|
7155
|
+
echo " info Show provider details (--json: capability contract)"
|
|
7156
|
+
echo " matrix Show the capability matrix per provider and engine"
|
|
7137
7157
|
echo " models Show resolved model configuration for all providers"
|
|
7138
7158
|
echo ""
|
|
7139
7159
|
echo "Precedence (highest wins):"
|
|
@@ -10865,7 +10885,7 @@ cmd_run() {
|
|
|
10865
10885
|
echo " --no-dashboard Disable web dashboard"
|
|
10866
10886
|
echo " --sandbox Run in Docker sandbox (default: off; requires Docker)"
|
|
10867
10887
|
echo " --no-plan Skip auto-shown PRD analysis at startup"
|
|
10868
|
-
echo " --budget USD
|
|
10888
|
+
echo " --budget USD Per-run cost cap (default $(loki_budget_default_usd))"
|
|
10869
10889
|
echo ""
|
|
10870
10890
|
echo "Progressive Isolation:"
|
|
10871
10891
|
echo " --worktree, -w Git worktree isolation (separate branch)"
|
|
@@ -13475,6 +13495,100 @@ cmd_config_path() {
|
|
|
13475
13495
|
echo "Create a config file with: loki config init"
|
|
13476
13496
|
}
|
|
13477
13497
|
|
|
13498
|
+
# Merge the Loki plugin into a Claude Code settings.json (loki setup-skill --claude-code).
|
|
13499
|
+
# Existing keys are never overwritten, invalid JSON is refused (rc 3), writes are atomic.
|
|
13500
|
+
_setup_skill_claude_code() {
|
|
13501
|
+
local print_only=0 project=0 stop=0 settings=""
|
|
13502
|
+
while [ $# -gt 0 ]; do
|
|
13503
|
+
case "$1" in
|
|
13504
|
+
--print) print_only=1 ;;
|
|
13505
|
+
--project) project=1 ;;
|
|
13506
|
+
--stop-hook) stop=1 ;;
|
|
13507
|
+
--settings) settings="${2:-}"; shift ;;
|
|
13508
|
+
--help|-h)
|
|
13509
|
+
echo "Usage: loki setup-skill --claude-code [--print] [--project] [--stop-hook] [--settings FILE]"
|
|
13510
|
+
echo ""
|
|
13511
|
+
echo "Registers the Loki plugin marketplace and enables the plugin in Claude Code"
|
|
13512
|
+
echo "settings (default ~/.claude/settings.json; --project uses ./.claude/settings.json)."
|
|
13513
|
+
echo "Merges only: existing keys are kept, invalid JSON is refused."
|
|
13514
|
+
echo ""
|
|
13515
|
+
echo " --print Print the settings snippet and change nothing"
|
|
13516
|
+
echo " --stop-hook Also opt in to the Stop-hook fast verifier (LOKI_STOP_VERIFY=1)"
|
|
13517
|
+
return 0
|
|
13518
|
+
;;
|
|
13519
|
+
*) echo "Unknown option: $1" >&2; return 2 ;;
|
|
13520
|
+
esac
|
|
13521
|
+
shift
|
|
13522
|
+
done
|
|
13523
|
+
command -v python3 >/dev/null 2>&1 || { echo "python3 is required" >&2; return 1; }
|
|
13524
|
+
if [ -z "$settings" ] && [ "$print_only" -eq 0 ]; then
|
|
13525
|
+
if [ "$project" -eq 1 ]; then
|
|
13526
|
+
settings="${TARGET_DIR:-.}/.claude/settings.json"
|
|
13527
|
+
else
|
|
13528
|
+
settings="$HOME/.claude/settings.json"
|
|
13529
|
+
fi
|
|
13530
|
+
fi
|
|
13531
|
+
local out rc
|
|
13532
|
+
out="$(python3 - "$settings" "$stop" "$print_only" <<'PY'
|
|
13533
|
+
import json, os, sys, tempfile
|
|
13534
|
+
path, stop, print_only = sys.argv[1], sys.argv[2] == "1", sys.argv[3] == "1"
|
|
13535
|
+
want = {
|
|
13536
|
+
"extraKnownMarketplaces": {
|
|
13537
|
+
"loki-mode": {"source": {"source": "github", "repo": "asklokesh/loki-mode"}}
|
|
13538
|
+
},
|
|
13539
|
+
"enabledPlugins": {"loki-mode@loki-mode": True},
|
|
13540
|
+
}
|
|
13541
|
+
if stop:
|
|
13542
|
+
want["env"] = {"LOKI_STOP_VERIFY": "1"}
|
|
13543
|
+
if print_only:
|
|
13544
|
+
print(json.dumps(want, indent=2))
|
|
13545
|
+
sys.exit(0)
|
|
13546
|
+
cur = {}
|
|
13547
|
+
if os.path.exists(path):
|
|
13548
|
+
try:
|
|
13549
|
+
raw = open(path).read()
|
|
13550
|
+
cur = json.loads(raw) if raw.strip() else {}
|
|
13551
|
+
except Exception as e:
|
|
13552
|
+
print("REFUSED %s is not valid JSON (%s); fix or move it aside" % (path, e))
|
|
13553
|
+
sys.exit(3)
|
|
13554
|
+
if not isinstance(cur, dict):
|
|
13555
|
+
print("REFUSED %s top level is not an object" % path)
|
|
13556
|
+
sys.exit(3)
|
|
13557
|
+
added = []
|
|
13558
|
+
for top, kv in want.items():
|
|
13559
|
+
node = cur.get(top)
|
|
13560
|
+
if node is None:
|
|
13561
|
+
cur[top] = {}
|
|
13562
|
+
node = cur[top]
|
|
13563
|
+
elif not isinstance(node, dict):
|
|
13564
|
+
print("KEPT %s (existing value is not an object)" % top)
|
|
13565
|
+
continue
|
|
13566
|
+
for k, v in kv.items():
|
|
13567
|
+
if k in node:
|
|
13568
|
+
print("KEPT %s.%s" % (top, k))
|
|
13569
|
+
else:
|
|
13570
|
+
node[k] = v
|
|
13571
|
+
added.append("%s.%s" % (top, k))
|
|
13572
|
+
print("ADDED %s.%s" % (top, k))
|
|
13573
|
+
if added:
|
|
13574
|
+
d = os.path.dirname(os.path.abspath(path))
|
|
13575
|
+
os.makedirs(d, exist_ok=True)
|
|
13576
|
+
fd, tmp = tempfile.mkstemp(dir=d, prefix=".settings.", suffix=".tmp")
|
|
13577
|
+
with os.fdopen(fd, "w") as f:
|
|
13578
|
+
json.dump(cur, f, indent=2)
|
|
13579
|
+
f.write("\n")
|
|
13580
|
+
os.replace(tmp, path)
|
|
13581
|
+
else:
|
|
13582
|
+
print("UNCHANGED %s" % path)
|
|
13583
|
+
PY
|
|
13584
|
+
)"
|
|
13585
|
+
rc=$?
|
|
13586
|
+
printf '%s\n' "$out"
|
|
13587
|
+
[ "$rc" -eq 0 ] || return "$rc"
|
|
13588
|
+
[ "$print_only" -eq 1 ] || echo "Next: in Claude Code run /reload-plugins, then try /loki-mode:start, /loki-mode:loki-verify, /loki-mode:handoff."
|
|
13589
|
+
return 0
|
|
13590
|
+
}
|
|
13591
|
+
|
|
13478
13592
|
# Set up skill symlinks for all providers
|
|
13479
13593
|
cmd_setup_skill() {
|
|
13480
13594
|
# v7.6.2 B-13 fix: --help must print help, not install skills.
|
|
@@ -13488,11 +13602,17 @@ cmd_setup_skill() {
|
|
|
13488
13602
|
echo "skills directory: ~/.claude/skills/, ~/.codex/skills/, etc."
|
|
13489
13603
|
echo ""
|
|
13490
13604
|
echo "Options:"
|
|
13605
|
+
echo " --claude-code Merge the Loki plugin into Claude Code settings (see --claude-code --help)"
|
|
13491
13606
|
echo " --help, -h Show this help and exit"
|
|
13492
13607
|
echo ""
|
|
13493
13608
|
echo "Side effects: writes symlinks/files under ~/.<provider>/skills/loki-mode/."
|
|
13494
13609
|
return 0
|
|
13495
13610
|
;;
|
|
13611
|
+
--claude-code)
|
|
13612
|
+
shift
|
|
13613
|
+
_setup_skill_claude_code "$@"
|
|
13614
|
+
return $?
|
|
13615
|
+
;;
|
|
13496
13616
|
esac
|
|
13497
13617
|
echo -e "${BOLD}Loki Mode Skill Setup${NC}"
|
|
13498
13618
|
echo ""
|
|
@@ -14080,6 +14200,18 @@ _loki_bun_delegate() {
|
|
|
14080
14200
|
exec "$bun_bin" "$cli" "$cmd" "$@"
|
|
14081
14201
|
}
|
|
14082
14202
|
|
|
14203
|
+
# One-line fix for a requirement id (a provider name is an id), read from the shared
|
|
14204
|
+
# table autonomy/lib/setup-requirements.json so runtime errors match loki doctor.
|
|
14205
|
+
_loki_req_fix_line() {
|
|
14206
|
+
local _id="$1" _fix=""
|
|
14207
|
+
_fix="$(jq -r --arg id "$_id" '.requirements[] | select(.id == $id) | .fix' "${SKILL_DIR}/autonomy/lib/setup-requirements.json" 2>/dev/null | head -n 1)" || _fix=""
|
|
14208
|
+
if [ -n "$_fix" ]; then
|
|
14209
|
+
echo " $_fix"
|
|
14210
|
+
else
|
|
14211
|
+
echo " Check the provider documentation for installation."
|
|
14212
|
+
fi
|
|
14213
|
+
}
|
|
14214
|
+
|
|
14083
14215
|
# loki doctor. The one implementation is loki-ts/src/commands/doctor.ts; this is a
|
|
14084
14216
|
# delegator. Only --airgap stays in bash (_loki_airgap_audit). If the Bun route is
|
|
14085
14217
|
# unavailable we print a minimal diagnostic (never a second copy of the checks).
|
|
@@ -14125,7 +14257,12 @@ cmd_doctor_json() {
|
|
|
14125
14257
|
why="${why//\\/\\\\}"; why="${why//\"/\\\"}"
|
|
14126
14258
|
fix="${fix//\\/\\\\}"; fix="${fix//\"/\\\"}"
|
|
14127
14259
|
ver="${ver//\\/\\\\}"; ver="${ver//\"/\\\"}"
|
|
14128
|
-
|
|
14260
|
+
local reqs=null
|
|
14261
|
+
if declare -F loki_requirements_json >/dev/null 2>&1; then
|
|
14262
|
+
reqs="$(loki_requirements_json 2>/dev/null | jq -c . 2>/dev/null)" || reqs=null
|
|
14263
|
+
[ -n "$reqs" ] || reqs=null
|
|
14264
|
+
fi
|
|
14265
|
+
printf '{"loki_mode_version":"%s","checks":[],"provider_availability":null,"disk":null,"ai_provider":null,"skills":[],"sentrux":null,"memory":null,"model_catalog":null,"requirements":%s,"summary":{"passed":0,"failed":1,"warnings":0,"ok":false},"route":"unavailable","reason":"%s","fix":"%s"}\n' "$ver" "$reqs" "$why" "$fix"
|
|
14129
14266
|
}
|
|
14130
14267
|
|
|
14131
14268
|
# Architectural-drift gate (v7.5.14, opt-in).
|
|
@@ -15686,15 +15823,6 @@ cmd_quick() {
|
|
|
15686
15823
|
exit 64
|
|
15687
15824
|
fi
|
|
15688
15825
|
|
|
15689
|
-
# v7.29.0: provider pre-flight gate. Offer install on a TTY; print honest
|
|
15690
|
-
# manual instructions and exit 2 on non-TTY/CI, before any spend. --help and
|
|
15691
|
-
# the no-args usage path already returned/exited above.
|
|
15692
|
-
if declare -f provider_offer_gate >/dev/null 2>&1; then
|
|
15693
|
-
if ! provider_offer_gate; then
|
|
15694
|
-
exit 2
|
|
15695
|
-
fi
|
|
15696
|
-
fi
|
|
15697
|
-
|
|
15698
15826
|
# #691: drop the unified config-file aliases from the task description. The
|
|
15699
15827
|
# main() pre-pass already applied the file; without this, a trailing
|
|
15700
15828
|
# `--config f.env` would be swept into task_desc (cmd_quick has no arg loop).
|
|
@@ -15711,6 +15839,12 @@ cmd_quick() {
|
|
|
15711
15839
|
--verbose|-v) if [ "$_quick_task_seen" = "false" ]; then export LOKI_VERBOSE=1; continue; fi ;;
|
|
15712
15840
|
--config|--vars|--env-file) _skip_next=true; continue ;;
|
|
15713
15841
|
--config=*|--vars=*|--env-file=*) continue ;;
|
|
15842
|
+
# LM-006: a leading unknown --flag is a usage error, never task text (a typo must not start a paid run).
|
|
15843
|
+
--?*) if [ "$_quick_task_seen" = "false" ] &&[[ "$_qa" != *" "* ]]; then
|
|
15844
|
+
echo -e "${RED}Error: unknown option: $_qa${NC}" >&2
|
|
15845
|
+
echo "Usage: loki quick [--verbose] \"description of what to do\"" >&2
|
|
15846
|
+
exit 64
|
|
15847
|
+
fi ;;
|
|
15714
15848
|
esac
|
|
15715
15849
|
_quick_task_seen=true
|
|
15716
15850
|
_quick_args+=("$_qa")
|
|
@@ -15722,6 +15856,16 @@ cmd_quick() {
|
|
|
15722
15856
|
exit 64
|
|
15723
15857
|
fi
|
|
15724
15858
|
|
|
15859
|
+
# v7.29.0: provider pre-flight gate. Offer install on a TTY; print honest
|
|
15860
|
+
# manual instructions and exit 2 on non-TTY/CI, before any spend. --help and
|
|
15861
|
+
# every usage error (no task, unknown option, exit 64) is decided above,
|
|
15862
|
+
# so a host with no provider still reports a typo as 64, not 2.
|
|
15863
|
+
if declare -f provider_offer_gate >/dev/null 2>&1; then
|
|
15864
|
+
if ! provider_offer_gate; then
|
|
15865
|
+
exit 2
|
|
15866
|
+
fi
|
|
15867
|
+
fi
|
|
15868
|
+
|
|
15725
15869
|
local task_desc="$*"
|
|
15726
15870
|
local version=$(get_version)
|
|
15727
15871
|
local max_iter="${LOKI_MAX_ITERATIONS:-3}"
|
|
@@ -15786,14 +15930,8 @@ QPRDEOF
|
|
|
15786
15930
|
if ! command -v "$_quick_provider" &>/dev/null; then
|
|
15787
15931
|
echo -e "${RED}Error: Provider CLI '$_quick_provider' is not installed.${NC}"
|
|
15788
15932
|
echo ""
|
|
15789
|
-
echo "Install your AI provider CLI first:"
|
|
15790
|
-
|
|
15791
|
-
claude) echo " npm install -g @anthropic-ai/claude-code" ;;
|
|
15792
|
-
codex) echo " npm install -g @openai/codex" ;;
|
|
15793
|
-
cline) echo " npm install -g cline" ;;
|
|
15794
|
-
aider) echo " pip install aider-chat" ;;
|
|
15795
|
-
*) echo " Check the provider documentation for installation." ;;
|
|
15796
|
-
esac
|
|
15933
|
+
echo "Install your AI provider CLI first (same fix as loki doctor):"
|
|
15934
|
+
_loki_req_fix_line "$_quick_provider"
|
|
15797
15935
|
echo ""
|
|
15798
15936
|
echo "Then verify: loki doctor"
|
|
15799
15937
|
exit 1
|
|
@@ -20708,8 +20846,33 @@ print()
|
|
|
20708
20846
|
# Dry-run PRD analysis and cost estimation (v6.18.0; refactored v6.81.1)
|
|
20709
20847
|
# Thin wrapper around show_prd_plan() so the same analysis is reusable from
|
|
20710
20848
|
# `loki start`, `loki run`, and other commands without duplicated code.
|
|
20849
|
+
# Read-only view of .loki/state/requirements-map.json (REQTRACE; contract: docs/spec-first-intent.md).
|
|
20850
|
+
_plan_show_requirements() {
|
|
20851
|
+
local as_json="${1:-false}" map="${LOKI_DIR:-.loki}/state/requirements-map.json"
|
|
20852
|
+
if [ ! -s "$map" ]; then
|
|
20853
|
+
if [ "$as_json" = true ]; then printf '{"error":"no requirements map","path":"%s"}\n' "$map"; return 1; fi
|
|
20854
|
+
echo "No requirements map at $map (written after a run that had a PRD checklist, a spec, or a multi-requirement PRD)."
|
|
20855
|
+
return 1
|
|
20856
|
+
fi
|
|
20857
|
+
if [ "$as_json" = true ]; then cat "$map"; return 0; fi
|
|
20858
|
+
LOKI_RM="$map" python3 -I -c "
|
|
20859
|
+
import json, os, sys
|
|
20860
|
+
try:
|
|
20861
|
+
m = json.load(open(os.environ['LOKI_RM']))
|
|
20862
|
+
reqs = m['requirements']
|
|
20863
|
+
except Exception:
|
|
20864
|
+
print('requirements map is unreadable: ' + os.environ['LOKI_RM']); sys.exit(1)
|
|
20865
|
+
cov = sum(1 for r in reqs if r.get('status') == 'covered')
|
|
20866
|
+
print('Requirements: %d/%d covered (revision %s)' % (cov, len(reqs), str(m.get('revision', ''))[:12]))
|
|
20867
|
+
for r in reqs:
|
|
20868
|
+
chk = (' <- ' + ', '.join(r.get('checks', []))) if r.get('checks') else ''
|
|
20869
|
+
print(' %s %-9s %-9s %s%s' % (r.get('id'), r.get('status'), r.get('method'), str(r.get('text', ''))[:80], chk))
|
|
20870
|
+
"
|
|
20871
|
+
}
|
|
20872
|
+
|
|
20711
20873
|
cmd_plan() {
|
|
20712
20874
|
local prd_file=""
|
|
20875
|
+
local show_requirements=false
|
|
20713
20876
|
local show_json=false
|
|
20714
20877
|
local show_verbose=false
|
|
20715
20878
|
|
|
@@ -20726,6 +20889,7 @@ cmd_plan() {
|
|
|
20726
20889
|
echo "Options:"
|
|
20727
20890
|
echo " --json Machine-readable JSON output"
|
|
20728
20891
|
echo " --spec With a task: write the acceptance criteria to .loki/specs/<slug>.md for you to edit"
|
|
20892
|
+
echo " --requirements Print the last run's requirement-to-check map (.loki/state/requirements-map.json), read-only"
|
|
20729
20893
|
echo " --verbose Show detailed per-iteration breakdown"
|
|
20730
20894
|
echo " --help, -h Show this help"
|
|
20731
20895
|
echo ""
|
|
@@ -20743,6 +20907,7 @@ cmd_plan() {
|
|
|
20743
20907
|
;;
|
|
20744
20908
|
--json) show_json=true; shift ;;
|
|
20745
20909
|
--verbose) show_verbose=true; shift ;;
|
|
20910
|
+
--requirements) show_requirements=true; shift ;;
|
|
20746
20911
|
*)
|
|
20747
20912
|
if [ -z "$prd_file" ]; then
|
|
20748
20913
|
prd_file="$1"
|
|
@@ -20752,6 +20917,11 @@ cmd_plan() {
|
|
|
20752
20917
|
esac
|
|
20753
20918
|
done
|
|
20754
20919
|
|
|
20920
|
+
if [ "$show_requirements" = true ]; then
|
|
20921
|
+
_plan_show_requirements "$show_json"
|
|
20922
|
+
return $?
|
|
20923
|
+
fi
|
|
20924
|
+
|
|
20755
20925
|
if [ -z "$prd_file" ]; then
|
|
20756
20926
|
# Under --json, a machine consumer expects JSON on every path, including
|
|
20757
20927
|
# errors -- never ANSI-colored prose. Emit a structured error to stdout.
|
|
@@ -36094,7 +36264,7 @@ PYEOF
|
|
|
36094
36264
|
}
|
|
36095
36265
|
|
|
36096
36266
|
# loki bench - head-to-head benchmark harness (R2).
|
|
36097
|
-
# Subcommands: run <task> | vs <task> | list | verify <result.json
|
|
36267
|
+
# Subcommands: run <task> | vs <task> | list | verify <result.json> | attribution.
|
|
36098
36268
|
# Thin pass-through to benchmarks/bench/run.sh (shared python core runner.py).
|
|
36099
36269
|
# CREDIBILITY: Loki NEVER grades its own success. Success is decided by a
|
|
36100
36270
|
# held-out acceptance command run by the grader OUTSIDE the agent (exit code).
|
|
@@ -36128,6 +36298,7 @@ cmd_bench() {
|
|
|
36128
36298
|
echo " verify <file> Recompute task_hash + check tool versions for a result.json"
|
|
36129
36299
|
echo " oracles Are the graders trustworthy? Hash-bound, no spend, no provider"
|
|
36130
36300
|
echo " report <files> Build results.json + RESULTS.md from per-tool result-rows"
|
|
36301
|
+
echo " attribution Same-model harness attribution: raw Claude Code vs Loki (--dry-run, --execute)"
|
|
36131
36302
|
echo ""
|
|
36132
36303
|
echo "Options:"
|
|
36133
36304
|
echo " --trials N Number of trials per tool (default 3)"
|
|
@@ -36324,7 +36495,9 @@ cmd_proof() {
|
|
|
36324
36495
|
echo " reads UNKNOWN when it cannot be computed"
|
|
36325
36496
|
echo " phases [--json] Measured phase history from real phase_change"
|
|
36326
36497
|
echo " events; unrecorded boundaries read UNKNOWN"
|
|
36327
|
-
echo " show <id>
|
|
36498
|
+
echo " show <id> [--json] Compact reviewer summary (label, revision, checks,"
|
|
36499
|
+
echo " requirements, modified tests); --json prints the"
|
|
36500
|
+
echo " full .loki/proofs/<id>/proof.json"
|
|
36328
36501
|
echo " verify <id> Re-check a receipt against the repo (tamper + drift)."
|
|
36329
36502
|
echo " Exit 0 clean, 1 tamper/drift, 2 could not check,"
|
|
36330
36503
|
echo " 64 usage (no id, more than one id, unknown option,"
|
|
@@ -36496,6 +36669,14 @@ PYEOF
|
|
|
36496
36669
|
exit 0
|
|
36497
36670
|
;;
|
|
36498
36671
|
show)
|
|
36672
|
+
local _ps_json=0 _ps_a _ps_args=()
|
|
36673
|
+
for _ps_a in "$@"; do
|
|
36674
|
+
case "$_ps_a" in
|
|
36675
|
+
--json) _ps_json=1 ;;
|
|
36676
|
+
*) _ps_args+=("$_ps_a") ;;
|
|
36677
|
+
esac
|
|
36678
|
+
done
|
|
36679
|
+
set -- "${_ps_args[@]+"${_ps_args[@]}"}"
|
|
36499
36680
|
local id="${1:-}"
|
|
36500
36681
|
if [ -z "$id" ]; then
|
|
36501
36682
|
echo -e "${RED}Missing proof id.${NC} Use 'loki proof list'."
|
|
@@ -36507,6 +36688,21 @@ PYEOF
|
|
|
36507
36688
|
echo "Use 'loki proof list' to see available proofs."
|
|
36508
36689
|
exit 1
|
|
36509
36690
|
fi
|
|
36691
|
+
if [ "$_ps_json" -eq 0 ]; then
|
|
36692
|
+
# Compact reviewer summary (docs/PROOF-PASSPORT.md).
|
|
36693
|
+
local _ps_py _ps_vr="${_LOKI_SCRIPT_DIR}/lib/proof-verify.py"
|
|
36694
|
+
_ps_py="$(loki_verify_tool_path python3)" || {
|
|
36695
|
+
echo -e "${RED}python3 is unavailable${NC}" >&2
|
|
36696
|
+
exit 2
|
|
36697
|
+
}
|
|
36698
|
+
local _ps_root
|
|
36699
|
+
_ps_root="$(loki_verify_root 2>/dev/null)" || {
|
|
36700
|
+
echo -e "${YELLOW}Summary unavailable (project tree not resolved; not checking the ambient cwd).${NC} Use 'loki proof show ${id} --json' for the full record." >&2
|
|
36701
|
+
exit 2
|
|
36702
|
+
}
|
|
36703
|
+
"$_ps_py" -E "$_ps_vr" summary "$pj" --repo "$_ps_root" --loki-dir "$loki_dir" || exit $?
|
|
36704
|
+
exit 0
|
|
36705
|
+
fi
|
|
36510
36706
|
if command -v jq &>/dev/null; then
|
|
36511
36707
|
jq . "$pj"
|
|
36512
36708
|
else
|