loki-mode 11.4.2 → 11.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/lib/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 +244 -237
- package/autonomy/notification-checker.py +1 -1
- 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 +3 -10
- package/dashboard/control.py +5 -435
- package/docs/ARCHITECTURE.md +1 -2
- package/docs/CLI-CORE-VERBS.md +2 -6
- package/docs/CLI-REFERENCE.md +3 -1
- package/docs/COMPONENTS.md +0 -2
- 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/authentication.md +19 -1
- package/docs/cost-controls.md +139 -0
- package/docs/dev/release-checklist.md +9 -8
- package/docs/enterprise/security.md +3 -234
- 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/ARCHITECT-CUTS.md +304 -0
- package/docs/v10/CLI-MODERN.md +2 -2
- package/docs/v10/DECISIONS.md +5 -5
- package/docs/v10/ENGINE.md +735 -267
- package/docs/v10/GUARDS.md +16 -14
- package/docs/v10/GUIDE.md +5 -7
- package/docs/v10/PROGRESS.md +12 -1
- package/docs/v11/MARKET-SLICES.md +1 -5
- package/integrations/openclaw/README.md +20 -0
- package/integrations/vibe-kanban.md +12 -50
- package/loki-ts/data/model-pricing.json +1 -0
- package/loki-ts/dist/loki.js +1156 -1103
- package/mcp/__init__.py +1 -1
- package/mcp/_sdk_loader.py +1 -1
- package/package.json +2 -2
- package/packages/control-plane/dist/server.js +2063 -1032
- 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/references/quality-control.md +1 -116
- package/skills/00-index.md +2 -2
- package/skills/artifacts.md +0 -22
- package/skills/production.md +2 -38
- package/web-app/dist/assets/{AdminPage-CYJ2BWRC.js → AdminPage-DhXdJNQk.js} +1 -1
- package/web-app/dist/assets/{Avatar-DdK4wynI.js → Avatar-ixVj76fM.js} +1 -1
- package/web-app/dist/assets/{Badge-CrX3MI7J.js → Badge-BGMSp22s.js} +1 -1
- package/web-app/dist/assets/{Button-709-wwGM.js → Button-pYJc32tG.js} +1 -1
- package/web-app/dist/assets/{CockpitPage-BapdTInO.js → CockpitPage-C1JBBouA.js} +1 -1
- package/web-app/dist/assets/{ComparePage-DT99pGvA.js → ComparePage-qD0NV4RK.js} +1 -1
- package/web-app/dist/assets/{ErrorBoundary-B0uJSys8.js → ErrorBoundary-C-yxO58j.js} +1 -1
- package/web-app/dist/assets/{EvidenceReceiptPanel-BtMFgElP.js → EvidenceReceiptPanel-ByPzuE1S.js} +1 -1
- package/web-app/dist/assets/{GitHubIssuesPanel-DjJuU941.js → GitHubIssuesPanel-BNv_2BEJ.js} +1 -1
- package/web-app/dist/assets/{GitHubPRsPanel-HXfEX1BC.js → GitHubPRsPanel-CuLZQ9CS.js} +1 -1
- package/web-app/dist/assets/{HomePage-Cqyves-S.js → HomePage-CS_FW8Je.js} +2 -2
- package/web-app/dist/assets/{LoginPage-jUbtC7_Y.js → LoginPage-DwiNf1Wm.js} +1 -1
- package/web-app/dist/assets/{MagicPage-DHRsqjgR.js → MagicPage-CmQybLPZ.js} +1 -1
- package/web-app/dist/assets/{MetricsPage-B-pED05R.js → MetricsPage-D9ERdpv8.js} +1 -1
- package/web-app/dist/assets/{NotFoundPage-CsbUs21R.js → NotFoundPage-D9ccgdbF.js} +1 -1
- package/web-app/dist/assets/{ProjectPage-BtlLEQwB.js → ProjectPage-B9Jslmgv.js} +3 -3
- package/web-app/dist/assets/{ProjectsPage-DaRbRjSp.js → ProjectsPage-DnU99Go2.js} +1 -1
- package/web-app/dist/assets/{SettingsPage-DALrtP3F.js → SettingsPage-DcTyx6wo.js} +1 -1
- package/web-app/dist/assets/{ShowcasePage-CoPHSNP0.js → ShowcasePage-jEY9ghSr.js} +1 -1
- package/web-app/dist/assets/{SystemSettingsPage-kOuSN50O.js → SystemSettingsPage-CSGltW-8.js} +1 -1
- package/web-app/dist/assets/{TeamsPage-DGWK0LMp.js → TeamsPage-gUuJXb9l.js} +1 -1
- package/web-app/dist/assets/{TemplatesPage-C-_10CwA.js → TemplatesPage-37Zhe--v.js} +1 -1
- package/web-app/dist/assets/{TerminalOutput-Cz_vPbXL.js → TerminalOutput-B09hRwaR.js} +1 -1
- package/web-app/dist/assets/{activity-icIsXJVa.js → activity-q_4MY9J0.js} +1 -1
- package/web-app/dist/assets/{bell-DbPR2_4r.js → bell-X8OC_PFP.js} +1 -1
- package/web-app/dist/assets/{bot-DvjP3Yh5.js → bot-C-N1PUOD.js} +1 -1
- package/web-app/dist/assets/{check-D1OBxHeU.js → check-B2c76Jmp.js} +1 -1
- package/web-app/dist/assets/{chevron-left-D09jDZ29.js → chevron-left-BF76YLNw.js} +1 -1
- package/web-app/dist/assets/{circle-alert-DyZMLOcC.js → circle-alert-AeFKBD8h.js} +1 -1
- package/web-app/dist/assets/{clock-CdpdJTId.js → clock-CiXRf-FH.js} +1 -1
- package/web-app/dist/assets/{cloud-CoLTlmoj.js → cloud-DKQ8SRJ5.js} +1 -1
- package/web-app/dist/assets/{code-xml-DrkE2ZZY.js → code-xml-DEb6jXWP.js} +1 -1
- package/web-app/dist/assets/{database-CMQQuM2R.js → database-6W7e-E9c.js} +1 -1
- package/web-app/dist/assets/{dollar-sign-CuioDaOG.js → dollar-sign-Ds2GOuyW.js} +1 -1
- package/web-app/dist/assets/{file-code-corner-Cx9j9K1S.js → file-code-corner-CZU0jg52.js} +1 -1
- package/web-app/dist/assets/{file-plus-CYD2zaaI.js → file-plus-DTVYnXCN.js} +1 -1
- package/web-app/dist/assets/{globe-6w-hnQkL.js → globe-0mUzKYDe.js} +1 -1
- package/web-app/dist/assets/{hammer-BpqtautL.js → hammer-BMHZg3YX.js} +1 -1
- package/web-app/dist/assets/{index-Dzs-9EgJ.js → index-BvOTvjax.js} +3 -3
- package/web-app/dist/assets/{layers-D5hd7jb7.js → layers-Df7TdcWB.js} +1 -1
- package/web-app/dist/assets/{loader-circle-C6Y9x_7H.js → loader-circle-kPsVfrSY.js} +1 -1
- package/web-app/dist/assets/{lock-D51L7rYh.js → lock-CXYcbEc5.js} +1 -1
- package/web-app/dist/assets/{package-BJF8hkP8.js → package-Cqhua1ID.js} +1 -1
- package/web-app/dist/assets/{plus-D5kUQ79n.js → plus-lseXhsn-.js} +1 -1
- package/web-app/dist/assets/{refresh-cw-BKdlCa7F.js → refresh-cw-OZriI6gD.js} +1 -1
- package/web-app/dist/assets/{rotate-ccw-_bd_YI1e.js → rotate-ccw-CKCfjPg8.js} +1 -1
- package/web-app/dist/assets/{scroll-text-DbkegIxF.js → scroll-text-DoVyyfKb.js} +1 -1
- package/web-app/dist/assets/{server-DAwqFIsq.js → server-DGy7TflW.js} +1 -1
- package/web-app/dist/assets/{shield-alert-BuR1tPHu.js → shield-alert-BCzRcMXi.js} +1 -1
- package/web-app/dist/assets/{thumbs-up-BF6p3mRd.js → thumbs-up-C_znJd5g.js} +1 -1
- package/web-app/dist/assets/{trash-2-BVpnkqqz.js → trash-2-BosCbeeA.js} +1 -1
- package/web-app/dist/assets/{trending-down-DpsDvRwW.js → trending-down-CkR5zDkV.js} +1 -1
- package/web-app/dist/assets/{trending-up-mFogTjt3.js → trending-up-DpUIfOH4.js} +1 -1
- package/web-app/dist/assets/{upload-4T8zpBsi.js → upload-CH9aKc8L.js} +1 -1
- package/web-app/dist/assets/{usePolling-DPXQv8WO.js → usePolling-pzxrHJeg.js} +1 -1
- package/web-app/dist/assets/{user-BYGIFaTm.js → user-B7OHa-VQ.js} +1 -1
- package/web-app/dist/index.html +1 -1
- package/dashboard/run.py +0 -63
- package/docs/openclaw-integration.md +0 -52
- package/docs/v10/HANDOFF-NEXT-WEEK.md +0 -40
- package/docs/v10/MORNING-BRIEF-1003.md +0 -25
- package/docs/v10/MORNING-BRIEF.md +0 -52
- package/docs/v10/TODO.md +0 -35
- package/mcp/resources.py +0 -351
- package/mcp/tools.py +0 -200
|
@@ -265,7 +265,7 @@ def check_quality_gate(trigger, loki_dir, iteration, notifications):
|
|
|
265
265
|
defect as the budget key, in the same file.
|
|
266
266
|
|
|
267
267
|
gate-failures.txt is the canonical failure source used by
|
|
268
|
-
proof-generator.py:413 and loki-ts
|
|
268
|
+
proof-generator.py:413 and loki-ts build_prompt.ts, so this
|
|
269
269
|
reuses a proven contract rather than introducing a second one.
|
|
270
270
|
"""
|
|
271
271
|
failures_file = Path(loki_dir) / "quality" / "gate-failures.txt"
|
|
@@ -80,6 +80,60 @@ detect_any_provider() {
|
|
|
80
80
|
return 1
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
+
# sdk_binary_present: true (0) when an executable Claude Agent SDK platform binary exists
|
|
84
|
+
# in an installed node_modules. Shared by detect_bundled_sdk_provider and
|
|
85
|
+
# loki_requirements_json.
|
|
86
|
+
sdk_binary_present() {
|
|
87
|
+
# Search the node_modules trees Loki is actually installed into. The root is
|
|
88
|
+
# derived from THIS FILE's location (self-containment contract, see header):
|
|
89
|
+
# SKILL_DIR belongs to autonomy/loki and is NOT exported, so it would be
|
|
90
|
+
# empty when doctor.ts spawns this script standalone -- which would silently
|
|
91
|
+
# answer "no SDK" on the Bun route while the bash route said yes, exactly the
|
|
92
|
+
# kind of route split the parity gate exists to prevent.
|
|
93
|
+
# LOKI_SDK_NODE_MODULES is a TEST-ONLY seam (never set in production) so the
|
|
94
|
+
# shell tests can point at a fixture tree without mutating real node_modules.
|
|
95
|
+
local _po_root
|
|
96
|
+
_po_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." 2>/dev/null && pwd)" || _po_root=""
|
|
97
|
+
# Array, not a word-split string: install roots can contain spaces.
|
|
98
|
+
local _po_search=()
|
|
99
|
+
if [ -n "${LOKI_SDK_NODE_MODULES:-}" ]; then
|
|
100
|
+
# When the test seam is set it is AUTHORITATIVE (not merely first): the
|
|
101
|
+
# real tree must not be consulted as a fallback, or a fixture asserting
|
|
102
|
+
# "no usable SDK" would silently pass by finding the repo's own binary.
|
|
103
|
+
_po_search=("$LOKI_SDK_NODE_MODULES")
|
|
104
|
+
elif [ -n "$_po_root" ]; then
|
|
105
|
+
# Two layouts, both real:
|
|
106
|
+
# repo clone -> <root>/node_modules, <root>/loki-ts/node_modules
|
|
107
|
+
# npm install -> npm HOISTS the SDK out of node_modules/loki-mode/
|
|
108
|
+
# up to the installing tree's top-level
|
|
109
|
+
# node_modules/ (verified by packing this repo and
|
|
110
|
+
# installing the tarball). Without the hoisted
|
|
111
|
+
# candidates the predicate silently returns 1 for
|
|
112
|
+
# every npm-installed user, i.e. the feature would
|
|
113
|
+
# be dead for exactly the audience it targets.
|
|
114
|
+
# <root> is .../node_modules/loki-mode, so ../ is the @scope-less
|
|
115
|
+
# top-level node_modules and ../../ covers a scoped install.
|
|
116
|
+
_po_search=(
|
|
117
|
+
"$_po_root/node_modules"
|
|
118
|
+
"$_po_root/loki-ts/node_modules"
|
|
119
|
+
"$_po_root/.."
|
|
120
|
+
"$_po_root/../.."
|
|
121
|
+
)
|
|
122
|
+
fi
|
|
123
|
+
local _nm
|
|
124
|
+
for _nm in ${_po_search+"${_po_search[@]}"}; do
|
|
125
|
+
[ -n "$_nm" ] || continue
|
|
126
|
+
set -- "$_nm"/@anthropic-ai/claude-agent-sdk-*/claude
|
|
127
|
+
# Unmatched globs stay literal in bash, so test the expansion for real.
|
|
128
|
+
while [ "$#" -gt 0 ]; do
|
|
129
|
+
[ -x "$1" ] && return 0
|
|
130
|
+
shift
|
|
131
|
+
done
|
|
132
|
+
done
|
|
133
|
+
return 1
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
|
|
83
137
|
# detect_bundled_sdk_provider: true (0) only when the bundled Claude Agent SDK
|
|
84
138
|
# can ACTUALLY run this machine's main loop with no separate CLI install.
|
|
85
139
|
#
|
|
@@ -130,53 +184,7 @@ detect_bundled_sdk_provider() {
|
|
|
130
184
|
return 1
|
|
131
185
|
fi
|
|
132
186
|
|
|
133
|
-
|
|
134
|
-
# derived from THIS FILE's location (self-containment contract, see header):
|
|
135
|
-
# SKILL_DIR belongs to autonomy/loki and is NOT exported, so it would be
|
|
136
|
-
# empty when doctor.ts spawns this script standalone -- which would silently
|
|
137
|
-
# answer "no SDK" on the Bun route while the bash route said yes, exactly the
|
|
138
|
-
# kind of route split the parity gate exists to prevent.
|
|
139
|
-
# LOKI_SDK_NODE_MODULES is a TEST-ONLY seam (never set in production) so the
|
|
140
|
-
# shell tests can point at a fixture tree without mutating real node_modules.
|
|
141
|
-
local _po_root
|
|
142
|
-
_po_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." 2>/dev/null && pwd)" || _po_root=""
|
|
143
|
-
# Array, not a word-split string: install roots can contain spaces.
|
|
144
|
-
local _po_search=()
|
|
145
|
-
if [ -n "${LOKI_SDK_NODE_MODULES:-}" ]; then
|
|
146
|
-
# When the test seam is set it is AUTHORITATIVE (not merely first): the
|
|
147
|
-
# real tree must not be consulted as a fallback, or a fixture asserting
|
|
148
|
-
# "no usable SDK" would silently pass by finding the repo's own binary.
|
|
149
|
-
_po_search=("$LOKI_SDK_NODE_MODULES")
|
|
150
|
-
elif [ -n "$_po_root" ]; then
|
|
151
|
-
# Two layouts, both real:
|
|
152
|
-
# repo clone -> <root>/node_modules, <root>/loki-ts/node_modules
|
|
153
|
-
# npm install -> npm HOISTS the SDK out of node_modules/loki-mode/
|
|
154
|
-
# up to the installing tree's top-level
|
|
155
|
-
# node_modules/ (verified by packing this repo and
|
|
156
|
-
# installing the tarball). Without the hoisted
|
|
157
|
-
# candidates the predicate silently returns 1 for
|
|
158
|
-
# every npm-installed user, i.e. the feature would
|
|
159
|
-
# be dead for exactly the audience it targets.
|
|
160
|
-
# <root> is .../node_modules/loki-mode, so ../ is the @scope-less
|
|
161
|
-
# top-level node_modules and ../../ covers a scoped install.
|
|
162
|
-
_po_search=(
|
|
163
|
-
"$_po_root/node_modules"
|
|
164
|
-
"$_po_root/loki-ts/node_modules"
|
|
165
|
-
"$_po_root/.."
|
|
166
|
-
"$_po_root/../.."
|
|
167
|
-
)
|
|
168
|
-
fi
|
|
169
|
-
local _nm
|
|
170
|
-
for _nm in ${_po_search+"${_po_search[@]}"}; do
|
|
171
|
-
[ -n "$_nm" ] || continue
|
|
172
|
-
set -- "$_nm"/@anthropic-ai/claude-agent-sdk-*/claude
|
|
173
|
-
# Unmatched globs stay literal in bash, so test the expansion for real.
|
|
174
|
-
while [ "$#" -gt 0 ]; do
|
|
175
|
-
[ -x "$1" ] && return 0
|
|
176
|
-
shift
|
|
177
|
-
done
|
|
178
|
-
done
|
|
179
|
-
return 1
|
|
187
|
+
sdk_binary_present
|
|
180
188
|
}
|
|
181
189
|
|
|
182
190
|
# _po_assume_yes: true when the user has opted into unattended confirmation.
|
|
@@ -545,6 +553,46 @@ print(json.dumps({"selected": selected, "providers": rows}, indent=2))
|
|
|
545
553
|
) || return 1
|
|
546
554
|
}
|
|
547
555
|
|
|
556
|
+
# loki_requirements_json: print the setup requirements report (shared table
|
|
557
|
+
# autonomy/lib/setup-requirements.json) as one JSON object, matching the "requirements"
|
|
558
|
+
# key of the Bun doctor (loki-ts/src/commands/doctor.ts). Used by the minimal
|
|
559
|
+
# `loki doctor --json` fallback when the Bun doctor cannot run. Presence only: unlike the
|
|
560
|
+
# Bun evaluator it does not compare versions.
|
|
561
|
+
loki_requirements_json() {
|
|
562
|
+
local table statuses="" id kind target values st v
|
|
563
|
+
table="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)/lib/setup-requirements.json"
|
|
564
|
+
if [ ! -f "$table" ] || ! command -v jq >/dev/null 2>&1; then
|
|
565
|
+
printf 'null\n'
|
|
566
|
+
return 0
|
|
567
|
+
fi
|
|
568
|
+
while IFS=$'\t' read -r id kind target values; do
|
|
569
|
+
st=missing
|
|
570
|
+
case "$kind" in
|
|
571
|
+
command) command -v "$target" >/dev/null 2>&1 && st=present ;;
|
|
572
|
+
env_any)
|
|
573
|
+
for v in ${target//,/ }; do [ -n "${!v:-}" ] && st=present; done ;;
|
|
574
|
+
env_value)
|
|
575
|
+
for v in ${target//,/ }; do
|
|
576
|
+
case ",${values}," in *",${!v:-},"*) [ -n "${!v:-}" ] && st=present ;; esac
|
|
577
|
+
done ;;
|
|
578
|
+
sdk_binary) sdk_binary_present && st=present ;;
|
|
579
|
+
esac
|
|
580
|
+
statuses="${statuses}${id} ${st}"$'\n'
|
|
581
|
+
done < <(jq -r '.requirements[] | [.id, .kind, (.target | if type == "array" then join(",") else . end), ((.values // []) | join(","))] | @tsv' "$table")
|
|
582
|
+
|
|
583
|
+
jq -n --rawfile st <(printf '%s' "$statuses") --slurpfile t "$table" '
|
|
584
|
+
($st | split("\n") | map(select(length > 0) | split(" ") | {(.[0]): .[1]}) | add) as $s
|
|
585
|
+
| $t[0] as $tab
|
|
586
|
+
| {paths: [ $tab.paths[] as $p
|
|
587
|
+
| ([ $tab.requirements[] | select(.path == $p.id)
|
|
588
|
+
| {id, label, level, status: $s[.id], detail: (if $s[.id] == "present" then null else "not found by presence check" end), fix} ]) as $items
|
|
589
|
+
| ([ $items[] | select(.level == "required") ]) as $req
|
|
590
|
+
| {id: $p.id, title: $p.title,
|
|
591
|
+
ready: (if ($req | length) > 0 then ($req | all(.status == "present")) else ($items | any(.status == "present")) end),
|
|
592
|
+
items: $items} ]}
|
|
593
|
+
| . + {first_task_ready: ((.paths[] | select(.id == "common") | .ready) and ([.paths[] | select(.id != "common") | .ready] | any))}'
|
|
594
|
+
}
|
|
595
|
+
|
|
548
596
|
# Executed directly (doctor.ts child_process bridge, or manual): run the offer.
|
|
549
597
|
# When sourced by autonomy/loki, this block does not run.
|
|
550
598
|
if [ "${BASH_SOURCE[0]}" = "$0" ]; then
|
package/autonomy/route.sh
CHANGED
|
@@ -45,7 +45,7 @@ loki_route_resolve() {
|
|
|
45
45
|
local verb="$1"; shift
|
|
46
46
|
R_DECIDED=0; R_E10=0; R_HARD=0; R_ENGINE=""; R_REASON=""; R_INPUT_TYPE=""; R_INPUT=""
|
|
47
47
|
R_PROVIDER=""; R_MODEL=""; R_NOTICE=""; R_ERR=""; R_EXPLAIN=0; R_JSON=0; R_SESSION_MODEL=""; R_VERB=""
|
|
48
|
-
R_E10_ARGS=(); R_CLEAN=()
|
|
48
|
+
R_E10_ARGS=(); R_CLEAN=(); R_ADAPTER=""; R_CAPDIFF=()
|
|
49
49
|
|
|
50
50
|
local a engine_req="" help=0 legacy_flag="" session_model="" provider_flag=""
|
|
51
51
|
local -a positionals=() passthru=()
|
|
@@ -208,21 +208,53 @@ loki_route_resolve() {
|
|
|
208
208
|
R_REASON="default: $R_INPUT_TYPE input runs on engine10 regardless of flag order"
|
|
209
209
|
fi
|
|
210
210
|
fi
|
|
211
|
+
_route_adapter_and_diffs "$legacy_flag"
|
|
211
212
|
return 0
|
|
212
213
|
}
|
|
213
214
|
|
|
215
|
+
# Sets R_ADAPTER and R_CAPDIFF[] from R_ENGINE / R_PROVIDER. Empty R_CAPDIFF means the
|
|
216
|
+
# full Claude Code path on the Loki 10 engine. Statements mirror providers/*.sh
|
|
217
|
+
# (PROVIDER_HAS_TASK_TOOL=false for every non-claude provider).
|
|
218
|
+
_route_adapter_and_diffs() {
|
|
219
|
+
local legacy_flag="$1"
|
|
220
|
+
R_CAPDIFF=()
|
|
221
|
+
if [ "$R_ENGINE" = "legacy" ]; then
|
|
222
|
+
R_ADAPTER="legacy-bash:$R_PROVIDER"
|
|
223
|
+
R_CAPDIFF+=("runs the previous bash loop (autonomy/run.sh) instead of the Loki 10 supervisor")
|
|
224
|
+
if [ -n "$legacy_flag" ]; then
|
|
225
|
+
R_CAPDIFF+=("honors $legacy_flag, which engine10 does not support")
|
|
226
|
+
fi
|
|
227
|
+
else
|
|
228
|
+
R_ADAPTER="engine10:$R_PROVIDER"
|
|
229
|
+
fi
|
|
230
|
+
case "$R_PROVIDER" in
|
|
231
|
+
claude) ;;
|
|
232
|
+
codex|cline|aider|opencode)
|
|
233
|
+
R_CAPDIFF+=("provider $R_PROVIDER has no Claude Code Task-tool subagents (providers/$R_PROVIDER.sh)") ;;
|
|
234
|
+
*)
|
|
235
|
+
R_CAPDIFF+=("provider $R_PROVIDER has no engine10 invoker") ;;
|
|
236
|
+
esac
|
|
237
|
+
}
|
|
238
|
+
|
|
214
239
|
# Print the route (human or --json). Returns 0.
|
|
215
240
|
loki_route_print() {
|
|
216
241
|
local shown="$R_INPUT"
|
|
217
242
|
if [ "${#shown}" -gt 72 ]; then shown="$(printf '%s' "$shown" | cut -c1-69)..."; fi
|
|
218
243
|
if [ "$R_JSON" = "1" ]; then
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
"$
|
|
244
|
+
local diffs="" d
|
|
245
|
+
for d in ${R_CAPDIFF[@]+"${R_CAPDIFF[@]}"}; do
|
|
246
|
+
diffs="${diffs:+$diffs,}\"$(_route_json_str "$d")\""
|
|
247
|
+
done
|
|
248
|
+
printf '{"engine":"%s","adapter":"%s","provider":"%s","model":"%s","input_type":"%s","input":"%s","reason":"%s","capability_differences":[%s]}\n' \
|
|
249
|
+
"$(_route_json_str "$R_ENGINE")" "$(_route_json_str "$R_ADAPTER")" "$(_route_json_str "$R_PROVIDER")" "$(_route_json_str "$R_MODEL")" \
|
|
250
|
+
"$(_route_json_str "$R_INPUT_TYPE")" "$(_route_json_str "$shown")" "$(_route_json_str "$R_REASON")" "$diffs"
|
|
222
251
|
else
|
|
223
|
-
printf 'engine: %s\nprovider: %s\nmodel: %s\ninput: %s (%s)\nreason: %s\n' \
|
|
224
|
-
"$R_ENGINE" "$R_PROVIDER" "$R_MODEL" "$R_INPUT_TYPE" "$shown" "$R_REASON"
|
|
252
|
+
printf 'engine: %s\nadapter: %s\nprovider: %s\nmodel: %s\ninput: %s (%s)\nreason: %s\n' \
|
|
253
|
+
"$R_ENGINE" "$R_ADAPTER" "$R_PROVIDER" "$R_MODEL" "$R_INPUT_TYPE" "$shown" "$R_REASON"
|
|
254
|
+
local d
|
|
255
|
+
for d in ${R_CAPDIFF[@]+"${R_CAPDIFF[@]}"}; do printf 'differs: %s\n' "$d"; done
|
|
225
256
|
fi
|
|
257
|
+
return 0
|
|
226
258
|
}
|
|
227
259
|
|
|
228
260
|
# Entry used by bin/loki. Args: the full original argv. Sets R_* and returns:
|
package/autonomy/run.sh
CHANGED
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
# LOKI_RESOURCE_MEM_THRESHOLD - Memory % threshold to warn (default: 80)
|
|
32
32
|
#
|
|
33
33
|
# Budget / Cost Limits (opt-in):
|
|
34
|
-
# LOKI_BUDGET_LIMIT - Max USD spend before auto-pause (default: empty = unlimited)
|
|
34
|
+
# LOKI_BUDGET_LIMIT - Max USD spend before auto-pause (default: loki-ts/data/model-pricing.json default_max_cost_usd, 100 USD; empty = unlimited)
|
|
35
35
|
# Example: "50.00" pauses session when estimated cost >= $50
|
|
36
36
|
#
|
|
37
37
|
# Security & Autonomy Controls (Enterprise):
|
|
@@ -532,7 +532,7 @@ for key, env_var in mapping.items():
|
|
|
532
532
|
val = get_nested(data, key) or data.get(key) or data.get(key.replace('.', '_'))
|
|
533
533
|
if val and isinstance(val, str):
|
|
534
534
|
safe_val = shlex.quote(val)
|
|
535
|
-
print(f'[ -z \"\${{{env_var}:-}}\" ] && export {env_var}={safe_val}')
|
|
535
|
+
print(f'[ -z \"\${{{env_var}:-}}\" ] && export {env_var}={safe_val}' + (\" && export LOKI_BUDGET_SOURCE=config\" if env_var == 'LOKI_BUDGET_LIMIT' else ''))
|
|
536
536
|
" 2>/dev/null)" 2>/dev/null || true
|
|
537
537
|
}
|
|
538
538
|
_LOKI_SETTINGS_FILE="${TARGET_DIR:-.}/.loki/config/settings.json" _load_json_settings
|
|
@@ -565,7 +565,23 @@ RESOURCE_MEM_THRESHOLD=${LOKI_RESOURCE_MEM_THRESHOLD:-80} # Memory % thresho
|
|
|
565
565
|
# it never kills work or discards a deliverable. The user removes .loki/PAUSE
|
|
566
566
|
# to resume, or raises LOKI_BUDGET_LIMIT. Set LOKI_BUDGET_LIMIT="" to restore
|
|
567
567
|
# the old unlimited behavior explicitly.
|
|
568
|
-
|
|
568
|
+
# LM-002: the default value is read from default_max_cost_usd in loki-ts/data/model-pricing.json, the same
|
|
569
|
+
# file the Loki 10 engine reads (docs/cost-controls.md). "100.00" is only the
|
|
570
|
+
# fallback when that file is absent, and budget_cap.test.ts pins it to the file.
|
|
571
|
+
_loki_budget_default="$(sed -n 's/.*"default_max_cost_usd"[[:space:]]*:[[:space:]]*\([0-9][0-9.]*\).*/\1/p' \
|
|
572
|
+
"${SCRIPT_DIR}/../loki-ts/data/model-pricing.json" 2>/dev/null | head -n 1)"
|
|
573
|
+
case "$_loki_budget_default" in
|
|
574
|
+
'' | *[!0-9.]*) _loki_budget_default="100.00" ;;
|
|
575
|
+
*) _loki_budget_default="$(awk -v v="$_loki_budget_default" 'BEGIN{printf "%.2f", v}')" ;;
|
|
576
|
+
esac
|
|
577
|
+
# Where the active cap came from: flag (loki start --budget), config (settings.json),
|
|
578
|
+
# env (LOKI_BUDGET_LIMIT set by the caller), or default. Printed once at run start.
|
|
579
|
+
if [ "${LOKI_BUDGET_LIMIT+set}" = "set" ]; then
|
|
580
|
+
BUDGET_SOURCE="${LOKI_BUDGET_SOURCE:-env}"
|
|
581
|
+
else
|
|
582
|
+
BUDGET_SOURCE="default"
|
|
583
|
+
fi
|
|
584
|
+
BUDGET_LIMIT=${LOKI_BUDGET_LIMIT-"$_loki_budget_default"} # USD. Note `-` not `:-`: an
|
|
569
585
|
# explicit empty value means the
|
|
570
586
|
# operator chose unlimited, and is
|
|
571
587
|
# honored.
|
|
@@ -7536,7 +7552,7 @@ EOF
|
|
|
7536
7552
|
"created_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
7537
7553
|
}
|
|
7538
7554
|
BUDGET_EOF
|
|
7539
|
-
log_info "Budget limit set: \$$BUDGET_LIMIT"
|
|
7555
|
+
log_info "Budget limit set: \$$BUDGET_LIMIT (source: ${BUDGET_SOURCE:-default})"
|
|
7540
7556
|
fi
|
|
7541
7557
|
|
|
7542
7558
|
# v7.0.0 Phase 2: remote->local hydrate. Runs ONCE at session boot (not
|
|
@@ -9041,21 +9057,25 @@ _read_iteration_cost() {
|
|
|
9041
9057
|
if [ -f "$result_cost_file" ]; then
|
|
9042
9058
|
python3 -c "
|
|
9043
9059
|
import json
|
|
9060
|
+
def _c(v):
|
|
9061
|
+
return v if isinstance(v, (int, float)) and not isinstance(v, bool) else 'unmeasured'
|
|
9044
9062
|
try:
|
|
9045
9063
|
d = json.load(open('$result_cost_file'))
|
|
9046
9064
|
print(
|
|
9047
9065
|
d.get('input_tokens', 0) or 0,
|
|
9048
9066
|
d.get('output_tokens', 0) or 0,
|
|
9049
|
-
d.get('total_cost_usd'
|
|
9067
|
+
_c(d.get('total_cost_usd')),
|
|
9050
9068
|
d.get('cache_read_tokens', 0) or 0,
|
|
9051
9069
|
d.get('cache_creation_tokens', 0) or 0,
|
|
9052
9070
|
)
|
|
9053
9071
|
except Exception:
|
|
9054
|
-
print(0, 0,
|
|
9055
|
-
" 2>/dev/null || echo "0 0
|
|
9072
|
+
print(0, 0, 'unmeasured', 0, 0)
|
|
9073
|
+
" 2>/dev/null || echo "0 0 unmeasured 0 0"
|
|
9056
9074
|
elif [ -f ".loki/context/tracking.json" ]; then
|
|
9057
9075
|
python3 -c "
|
|
9058
9076
|
import json
|
|
9077
|
+
def _c(v):
|
|
9078
|
+
return v if isinstance(v, (int, float)) and not isinstance(v, bool) else 'unmeasured'
|
|
9059
9079
|
try:
|
|
9060
9080
|
t = json.load(open('.loki/context/tracking.json'))
|
|
9061
9081
|
iters = t.get('per_iteration', [])
|
|
@@ -9065,17 +9085,17 @@ try:
|
|
|
9065
9085
|
print(
|
|
9066
9086
|
m.get('input_tokens', 0),
|
|
9067
9087
|
m.get('output_tokens', 0),
|
|
9068
|
-
m.get('cost_usd'
|
|
9088
|
+
_c(m.get('cost_usd')),
|
|
9069
9089
|
m.get('cache_read_tokens', 0),
|
|
9070
9090
|
m.get('cache_creation_tokens', 0),
|
|
9071
9091
|
)
|
|
9072
9092
|
else:
|
|
9073
|
-
print(0, 0,
|
|
9093
|
+
print(0, 0, 'unmeasured', 0, 0)
|
|
9074
9094
|
except Exception:
|
|
9075
|
-
print(0, 0,
|
|
9076
|
-
" 2>/dev/null || echo "0 0
|
|
9095
|
+
print(0, 0, 'unmeasured', 0, 0)
|
|
9096
|
+
" 2>/dev/null || echo "0 0 unmeasured 0 0"
|
|
9077
9097
|
else
|
|
9078
|
-
echo "0 0
|
|
9098
|
+
echo "0 0 unmeasured 0 0"
|
|
9079
9099
|
fi
|
|
9080
9100
|
}
|
|
9081
9101
|
|
|
@@ -9192,6 +9212,15 @@ track_iteration_complete() {
|
|
|
9192
9212
|
$iter_cost_line
|
|
9193
9213
|
ITER_COST_EOF
|
|
9194
9214
|
|
|
9215
|
+
# Unknown cost is omitted with a reason, never written as 0 (readers treat absence as unmeasured).
|
|
9216
|
+
local iter_cost_json
|
|
9217
|
+
case "${iter_cost:-unmeasured}" in
|
|
9218
|
+
unmeasured) iter_cost_json=' "cost_unmeasured_reason": "no dollar figure recorded for this iteration",
|
|
9219
|
+
' ;;
|
|
9220
|
+
*) iter_cost_json=" \"cost_usd\": ${iter_cost},
|
|
9221
|
+
" ;;
|
|
9222
|
+
esac
|
|
9223
|
+
|
|
9195
9224
|
cat > ".loki/metrics/efficiency/iteration-${iteration}.json" << EFF_EOF
|
|
9196
9225
|
{
|
|
9197
9226
|
"iteration": $iteration,
|
|
@@ -9204,8 +9233,7 @@ ITER_COST_EOF
|
|
|
9204
9233
|
"output_tokens": ${iter_output:-0},
|
|
9205
9234
|
"cache_read_tokens": ${iter_cache_read:-0},
|
|
9206
9235
|
"cache_creation_tokens": ${iter_cache_creation:-0},
|
|
9207
|
-
"
|
|
9208
|
-
"timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
9236
|
+
${iter_cost_json} "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
9209
9237
|
}
|
|
9210
9238
|
EFF_EOF
|
|
9211
9239
|
|
package/autonomy/setup-wizard.sh
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
# file. `loki welcome` (intro), `loki quickstart` (first build) and
|
|
5
5
|
# `loki doctor` (health) remain separate entry points.
|
|
6
6
|
#
|
|
7
|
-
# REQUIRED (doctor fails without them): node >=
|
|
7
|
+
# REQUIRED (doctor fails without them): node >= 20, python3 >= 3.8, jq, git, curl
|
|
8
8
|
# AT LEAST ONE of: a provider CLI (claude, codex, cline, aider, opencode) or the
|
|
9
9
|
# bundled Claude Agent SDK with credentials. Claude Code is the default.
|
|
10
10
|
# OPTIONAL: bun (bundled by npm), bash >= 4, codex/cline/aider/opencode, ollama.
|
|
@@ -31,6 +31,14 @@ _lsw_confirm() {
|
|
|
31
31
|
case "$ans" in y|Y|yes|YES) return 0 ;; *) return 1 ;; esac
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
_lsw_fix() {
|
|
35
|
+
# _lsw_fix ID FALLBACK -> the one-line fix from the shared requirements table
|
|
36
|
+
# (autonomy/lib/setup-requirements.json), the same text loki doctor prints.
|
|
37
|
+
local out=""
|
|
38
|
+
out="$(jq -r --arg id "$1" '.requirements[] | select(.id == $id) | .fix' "${SKILL_DIR}/autonomy/lib/setup-requirements.json" 2>/dev/null | head -n 1)" || out=""
|
|
39
|
+
printf '%s' "${out:-$2}"
|
|
40
|
+
}
|
|
41
|
+
|
|
34
42
|
_lsw_tool() {
|
|
35
43
|
# _lsw_tool NAME LABEL INSTALL_HINT
|
|
36
44
|
if command -v "$1" >/dev/null 2>&1; then
|
|
@@ -79,12 +87,12 @@ cmd_setup() {
|
|
|
79
87
|
echo "Loki Mode setup"
|
|
80
88
|
echo ""
|
|
81
89
|
echo "1. Required tools"
|
|
82
|
-
_lsw_tool node REQUIRED "
|
|
83
|
-
_lsw_tool python3 REQUIRED "
|
|
84
|
-
_lsw_tool jq REQUIRED "
|
|
85
|
-
_lsw_tool git REQUIRED "
|
|
86
|
-
_lsw_tool curl REQUIRED "
|
|
87
|
-
_lsw_tool bun OPTIONAL "bundled by npm; else see https://bun.sh" || true
|
|
90
|
+
_lsw_tool node REQUIRED "$(_lsw_fix node "install Node 20+ from https://nodejs.org")" || true
|
|
91
|
+
_lsw_tool python3 REQUIRED "$(_lsw_fix python3 "install python3")" || true
|
|
92
|
+
_lsw_tool jq REQUIRED "$(_lsw_fix jq "install jq")" || true
|
|
93
|
+
_lsw_tool git REQUIRED "$(_lsw_fix git "install git")" || true
|
|
94
|
+
_lsw_tool curl REQUIRED "$(_lsw_fix curl "install curl")" || true
|
|
95
|
+
_lsw_tool bun OPTIONAL "$(_lsw_fix bun "bundled by npm; else see https://bun.sh")" || true
|
|
88
96
|
if [ "$_LSW_MISSING" -gt 0 ]; then
|
|
89
97
|
echo ""
|
|
90
98
|
echo "Install the missing REQUIRED tools above with your package manager (setup never installs system packages), then rerun: loki setup"
|
|
@@ -95,7 +103,7 @@ cmd_setup() {
|
|
|
95
103
|
echo "2. Provider CLI (Claude Code is the default and the only Tier-1 provider)"
|
|
96
104
|
local p
|
|
97
105
|
for p in codex cline aider opencode; do
|
|
98
|
-
_lsw_tool "$p" OPTIONAL "see 'loki doctor' for the command" || true
|
|
106
|
+
_lsw_tool "$p" OPTIONAL "$(_lsw_fix "$p" "see 'loki doctor' for the command")" || true
|
|
99
107
|
done
|
|
100
108
|
if command -v claude >/dev/null 2>&1; then
|
|
101
109
|
printf ' [ OK ] %-10s DEFAULT\n' claude
|
|
@@ -108,7 +116,7 @@ cmd_setup() {
|
|
|
108
116
|
fi
|
|
109
117
|
fi
|
|
110
118
|
else
|
|
111
|
-
echo " [MISS] claude DEFAULT. Install: npm install -g @anthropic-ai/claude-code (then: claude auth login)"
|
|
119
|
+
echo " [MISS] claude DEFAULT. Install: $(_lsw_fix claude "npm install -g @anthropic-ai/claude-code") (then: claude auth login)"
|
|
112
120
|
if [ "$check_only" = 0 ] && [ -f "${SKILL_DIR}/autonomy/provider-offer.sh" ]; then
|
|
113
121
|
if _lsw_confirm "Run that install command now?"; then
|
|
114
122
|
# shellcheck disable=SC1091
|
|
@@ -118,7 +126,8 @@ cmd_setup() {
|
|
|
118
126
|
fi
|
|
119
127
|
if ! command -v claude >/dev/null 2>&1; then
|
|
120
128
|
echo " Claude Code is not mandatory if another provider above is installed,"
|
|
121
|
-
echo " or if the
|
|
129
|
+
echo " or if you use the Anthropic API-key path (LOKI_SDK_MODE=full with ANTHROPIC_API_KEY)."
|
|
130
|
+
echo " Requirements per path: loki doctor --requirements"
|
|
122
131
|
fi
|
|
123
132
|
fi
|
|
124
133
|
|
package/autonomy/verify.sh
CHANGED
|
@@ -2268,6 +2268,7 @@ verify_emit_evidence() {
|
|
|
2268
2268
|
_V_SCOPE_SOFT_NET="${VERIFY_SCOPE_SOFT_NET_LINES:-}" \
|
|
2269
2269
|
_V_SCOPE_MAX_FILES="${VERIFY_SCOPE_MAX_FILES:-}" \
|
|
2270
2270
|
_V_SCOPE_MAX_NET="${VERIFY_SCOPE_MAX_NET_LINES:-}" \
|
|
2271
|
+
_V_LIBDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/lib" \
|
|
2271
2272
|
_verify_py - <<'PYEOF'
|
|
2272
2273
|
import json, os, hashlib, sys
|
|
2273
2274
|
|
|
@@ -2401,6 +2402,27 @@ if _scope_verdict:
|
|
|
2401
2402
|
"thresholds": _thresholds,
|
|
2402
2403
|
}
|
|
2403
2404
|
|
|
2405
|
+
# Verification record (docs/PROOF-PASSPORT.md): integrity, execution
|
|
2406
|
+
# validity (revision + environment) and requirement coverage, kept separate, plus
|
|
2407
|
+
# per-check status and a scoped label. Additive; verdict/exit_code are untouched.
|
|
2408
|
+
# A failure to build it is recorded, never swallowed into a clean-looking doc.
|
|
2409
|
+
try:
|
|
2410
|
+
sys.path.insert(0, os.environ["_V_LIBDIR"])
|
|
2411
|
+
import importlib.util
|
|
2412
|
+
_spec = importlib.util.spec_from_file_location(
|
|
2413
|
+
"loki_proof_verify", os.path.join(os.environ["_V_LIBDIR"], "proof-verify.py"))
|
|
2414
|
+
_pv_mod = importlib.util.module_from_spec(_spec)
|
|
2415
|
+
_spec.loader.exec_module(_pv_mod)
|
|
2416
|
+
doc["verification"] = _pv_mod.build_for_evidence(
|
|
2417
|
+
doc, repo_dir=".", loki_dir=os.environ.get("LOKI_DIR") or ".loki",
|
|
2418
|
+
record_path="", fresh_capture=True)
|
|
2419
|
+
# base_verdict duplicates doc["verdict"]; record_path would pin the output
|
|
2420
|
+
# directory into a document that must be byte-identical across directories.
|
|
2421
|
+
doc["verification"].pop("base_verdict", None)
|
|
2422
|
+
except Exception as _vr_exc:
|
|
2423
|
+
doc["verification"] = {"schema_version": "1.0", "error": "verification record unavailable: %s" % _vr_exc,
|
|
2424
|
+
"label": doc["verdict"] + " (verification record unavailable)"}
|
|
2425
|
+
|
|
2404
2426
|
os.makedirs(out_dir, exist_ok=True)
|
|
2405
2427
|
ev_path = os.path.join(out_dir, "evidence.json")
|
|
2406
2428
|
with open(ev_path, "w") as f:
|
|
@@ -2437,6 +2459,10 @@ lines.append("# Autonomi Verify report")
|
|
|
2437
2459
|
lines.append("")
|
|
2438
2460
|
lines.append("Verdict: **%s** (exit %d)" % (doc["verdict"], doc["exit_code"]))
|
|
2439
2461
|
lines.append("")
|
|
2462
|
+
_vr_label = (doc.get("verification") or {}).get("label")
|
|
2463
|
+
if _vr_label:
|
|
2464
|
+
lines.append("Verification: %s" % _vr_label)
|
|
2465
|
+
lines.append("")
|
|
2440
2466
|
_llm = doc.get("llm_review") or {}
|
|
2441
2467
|
_llm_status = _llm.get("status", "unavailable")
|
|
2442
2468
|
if _llm_status == "reviewed":
|
|
@@ -3419,7 +3445,20 @@ verify_main() {
|
|
|
3419
3445
|
# Under --json stdout carries the evidence document alone, so the human
|
|
3420
3446
|
# banner is redirected to stderr rather than dropped: an operator watching a
|
|
3421
3447
|
# terminal still sees the verdict, and `| jq` still parses.
|
|
3422
|
-
|
|
3448
|
+
# Scoped label + compact reviewer summary from the verification record just
|
|
3449
|
+
# written to evidence.json. The exit code is unchanged; only the wording is
|
|
3450
|
+
# stricter: a skipped or not-run check never leaves a bare "VERIFIED".
|
|
3451
|
+
local _v_lib _v_label _v_summary
|
|
3452
|
+
_v_lib="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/lib"
|
|
3453
|
+
_v_label="$VERIFY_VERDICT"
|
|
3454
|
+
if [ -f "$_v_lib/proof-verify.py" ]; then
|
|
3455
|
+
_v_summary="$(_verify_py "$_v_lib/proof-verify.py" summary "$out_dir/evidence.json" --embedded 2>/dev/null)" || _v_summary=""
|
|
3456
|
+
if [ -n "$_v_summary" ]; then
|
|
3457
|
+
_v_label="${_v_summary%%$'\n'*}"
|
|
3458
|
+
printf '%s\n' "${_v_summary#*$'\n'}" >&$_v_banner_fd
|
|
3459
|
+
fi
|
|
3460
|
+
fi
|
|
3461
|
+
printf 'VERDICT: %s\n' "$_v_label" >&$_v_banner_fd
|
|
3423
3462
|
printf 'Evidence: %s/evidence.json\n' "$out_dir" >&$_v_banner_fd
|
|
3424
3463
|
printf 'Report: %s/report.md\n' "$out_dir" >&$_v_banner_fd
|
|
3425
3464
|
# --hosted only: surface the enrichment in human output so the extra signal
|
package/completions/_loki
CHANGED
|
@@ -378,7 +378,8 @@ function _loki_provider {
|
|
|
378
378
|
'show:Display current provider'
|
|
379
379
|
'set:Set default provider'
|
|
380
380
|
'list:List available providers'
|
|
381
|
-
'info:Get provider information'
|
|
381
|
+
'info:Get provider information (--json: capability contract)'
|
|
382
|
+
'matrix:Show the capability matrix'
|
|
382
383
|
'help:Provider help'
|
|
383
384
|
)
|
|
384
385
|
_describe -t cmds 'provider subcommand' cmds
|
|
@@ -389,6 +390,7 @@ function _loki_plan {
|
|
|
389
390
|
'--json[Machine-readable JSON output]' \
|
|
390
391
|
'--verbose[Detailed per-iteration breakdown]' \
|
|
391
392
|
'--spec[Write editable acceptance criteria to .loki/specs/<slug>.md]' \
|
|
393
|
+
'--requirements[Print the last run requirement-to-check map (read-only)]' \
|
|
392
394
|
'*:prd file:_files'
|
|
393
395
|
}
|
|
394
396
|
|
package/completions/loki.bash
CHANGED
|
@@ -67,7 +67,7 @@ _loki_completion() {
|
|
|
67
67
|
;;
|
|
68
68
|
|
|
69
69
|
provider)
|
|
70
|
-
local provider_cmds="show set list info help"
|
|
70
|
+
local provider_cmds="show set list info matrix help"
|
|
71
71
|
COMPREPLY=( $(compgen -W "${provider_cmds}" -- "$cur") )
|
|
72
72
|
;;
|
|
73
73
|
|
|
@@ -123,9 +123,15 @@ _loki_completion() {
|
|
|
123
123
|
fi
|
|
124
124
|
;;
|
|
125
125
|
|
|
126
|
+
setup-skill)
|
|
127
|
+
if [[ "$cur" == -* ]]; then
|
|
128
|
+
COMPREPLY=( $(compgen -W "--claude-code --print --project --stop-hook --settings --help" -- "$cur") )
|
|
129
|
+
return 0
|
|
130
|
+
fi
|
|
131
|
+
;;
|
|
126
132
|
doctor)
|
|
127
133
|
if [[ "$cur" == -* ]]; then
|
|
128
|
-
COMPREPLY=( $(compgen -W "--json --fix --help" -- "$cur") )
|
|
134
|
+
COMPREPLY=( $(compgen -W "--json --fix --repo --requirements --help" -- "$cur") )
|
|
129
135
|
return 0
|
|
130
136
|
fi
|
|
131
137
|
;;
|
|
@@ -197,7 +203,7 @@ _loki_completion() {
|
|
|
197
203
|
|
|
198
204
|
plan)
|
|
199
205
|
if [[ "$cur" == -* ]]; then
|
|
200
|
-
COMPREPLY=( $(compgen -W "--json --verbose --spec --help" -- "$cur") )
|
|
206
|
+
COMPREPLY=( $(compgen -W "--json --verbose --spec --requirements --help" -- "$cur") )
|
|
201
207
|
return 0
|
|
202
208
|
fi
|
|
203
209
|
;;
|
package/dashboard/__init__.py
CHANGED
|
@@ -4,16 +4,9 @@ Loki Mode Dashboard Backend
|
|
|
4
4
|
FastAPI-based dashboard for managing Loki Mode projects, tasks, and agents.
|
|
5
5
|
|
|
6
6
|
Modules:
|
|
7
|
-
control: Session control
|
|
7
|
+
control: Session control helpers (status, atomic writes, origin check)
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
|
-
__version__ = "11.
|
|
10
|
+
__version__ = "11.6.0"
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
try:
|
|
14
|
-
from .control import app as control_app
|
|
15
|
-
except ImportError:
|
|
16
|
-
# FastAPI not installed, control module not available
|
|
17
|
-
control_app = None
|
|
18
|
-
|
|
19
|
-
__all__ = ["control_app", "__version__"]
|
|
12
|
+
__all__ = ["__version__"]
|