loki-mode 7.118.0 → 7.119.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 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 v7.118.0
6
+ # Loki Mode v7.119.0
7
7
 
8
8
  **You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
9
9
 
@@ -408,4 +408,4 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
408
408
 
409
409
  ---
410
410
 
411
- **v7.118.0 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
411
+ **v7.119.0 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
package/VERSION CHANGED
@@ -1 +1 @@
1
- 7.118.0
1
+ 7.119.0
@@ -341,7 +341,20 @@ def _collect_build(loki_dir):
341
341
  out["exit_code"] = _to_int(ec, None) if ec is not None else None
342
342
  dur = raw.get("duration_sec")
343
343
  out["duration_sec"] = _to_float(dur, None) if dur is not None else None
344
- if not ran:
344
+ # HONEST APPLICABILITY (build has no writer historically -> facts.build was
345
+ # permanently "not_run" for every project, counting a CLI with no build step
346
+ # as a gap and dragging the headline to WITH GAPS). The writer now records a
347
+ # POSITIVE applicability signal: applicable:false means "this stack genuinely
348
+ # has no build phase" (a CLI, a plain script). That is N/A, not a skipped
349
+ # gap, so it must NOT be a degraded item. CRITICAL anti-fake-green rule:
350
+ # not_applicable ONLY from an EXPLICIT applicable:false in the file. An absent
351
+ # file or a missing/true applicable flag stays not_run (an honest gap) -- an
352
+ # un-built project must never flip green just because nobody wrote the file.
353
+ applicable = raw.get("applicable", True)
354
+ out["applicable"] = bool(applicable)
355
+ if applicable is False:
356
+ out["status"] = "not_applicable"
357
+ elif not ran:
345
358
  out["status"] = "not_run"
346
359
  elif out["exit_code"] == 0:
347
360
  out["status"] = "verified"
package/autonomy/run.sh CHANGED
@@ -8354,6 +8354,163 @@ COMPOUND_SCRIPT
8354
8354
  # Results stored in .loki/quality/static-analysis.json
8355
8355
  # ============================================================================
8356
8356
 
8357
+ # ---------------------------------------------------------------------------
8358
+ # enforce_build_check -- run the stack's build (if it has one) and record an
8359
+ # HONEST build fact for the Evidence Receipt (#47). Historically nothing wrote
8360
+ # .loki/quality/build-results.json, so facts.build was PERMANENTLY "not_run" for
8361
+ # every project -- a CLI with no build step read identically to a skipped real
8362
+ # build, and both dragged the receipt to "WITH GAPS". This is the missing writer.
8363
+ #
8364
+ # The distinction the receipt needs (and the founder demanded, no fabrication) is
8365
+ # THREE-WAY, not two (a council review caught the two-way version laundering
8366
+ # "unrecognized build system" into a fake N/A):
8367
+ # - a build command WE RUN exists (npm "build" / go / cargo) -> RUN it, record
8368
+ # ran/exit_code (verified on 0, failed otherwise -- a real gap kept honest).
8369
+ # - a build system EXISTS but we do not auto-run it (Make/Maven/Gradle/.NET, a
8370
+ # non-"build" npm script, a pyproject build-system) -> not_run (an HONEST GAP,
8371
+ # matching verify.sh:291's "skipped"). NEVER N/A -- a real, un-run build must
8372
+ # never read VERIFIED.
8373
+ # - genuinely NO build phase at all (a plain CLI/script) -> applicable:false
8374
+ # (status not_applicable). A POSITIVE "no build phase" determination, NOT an
8375
+ # absent file -- proof-generator maps applicable:false -> N/A (not a gap) but a
8376
+ # MISSING file or an unrecognized-real build stays not_run. One vocabulary, no
8377
+ # fake-green. Pinned by tests/test-build-check-applicability.sh.
8378
+ # ---------------------------------------------------------------------------
8379
+ enforce_build_check() {
8380
+ local tree="${TARGET_DIR:-.}"
8381
+ local loki_dir="$tree/.loki"
8382
+ local quality_dir="$loki_dir/quality"
8383
+ mkdir -p "$quality_dir"
8384
+ local out_file="$quality_dir/build-results.json"
8385
+ local timeout_s="${LOKI_GATE_TIMEOUT:-300}"
8386
+ local ts; ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
8387
+
8388
+ # THREE-WAY classification (detection is always cheap). The anti-fake-green line
8389
+ # (council-caught): N/A is ONLY for a POSITIVE "this stack has no build phase"
8390
+ # determination. An unrecognized-but-real build system (Make, Maven, Gradle,
8391
+ # .NET, a non-"build" npm build script) must stay an HONEST GAP (not_run), NOT
8392
+ # be laundered into N/A -- otherwise a real, un-run build reads VERIFIED. This
8393
+ # mirrors verify.sh:291, which records the same fall-through as a "skipped" gap.
8394
+ # runnable -> a build command WE run (npm build / go / cargo) -> verified/failed
8395
+ # present -> a build system EXISTS but we don't auto-run it -> not_run (GAP)
8396
+ # none -> positively no build phase at all -> not_applicable (N/A)
8397
+ local cmd="" ran="false" applicable="false" exit_code="null" status="not_run"
8398
+ local build_class="present"
8399
+
8400
+ # INVERTED classification (three council rounds each found a fake-green hole in
8401
+ # an allowlist of build systems -> the allowlist is structurally leaky). The
8402
+ # two error directions are NOT equal: a REAL build read as N/A -> VERIFIED is
8403
+ # DISHONEST over-claim (the cardinal fake-green sin); a no-build CLI read as a
8404
+ # not_run gap is an HONEST under-claim (merely the founder's original UX nit).
8405
+ # So not_run is the SAFE CATCH-ALL and N/A requires a POSITIVE proof-of-no-build.
8406
+ # A forgotten stack (Bazel, meson, autotools, Zig, Nix...) now falls to not_run
8407
+ # (honest), never to fake N/A -- fixing the whole CLASS, not each instance.
8408
+ # 1. runnable: a build command WE run -> verified/failed
8409
+ # 2. none: POSITIVE proof of no build phase -> not_applicable (N/A)
8410
+ # 3. else: not_run (honest gap) -- the default, covers every unknown stack
8411
+
8412
+ if [ -f "$tree/package.json" ] && grep -q '"build"[[:space:]]*:' "$tree/package.json" 2>/dev/null; then
8413
+ cmd="npm run build"; applicable="true"; build_class="runnable"
8414
+ elif [ -f "$tree/go.mod" ] && command -v go >/dev/null 2>&1; then
8415
+ cmd="go build ./..."; applicable="true"; build_class="runnable"
8416
+ elif [ -f "$tree/Cargo.toml" ] && command -v cargo >/dev/null 2>&1; then
8417
+ cmd="cargo build"; applicable="true"; build_class="runnable"
8418
+ else
8419
+ # POSITIVE proof-of-no-build (the ONLY path to N/A). Two narrow cases, and
8420
+ # anything short of a clear determination stays not_run:
8421
+ # (a) a package.json whose scripts exist but include NO build-ish script
8422
+ # AND there is no foreign build manifest -> a JS CLI/lib with no build.
8423
+ # (b) NO build manifest of ANY known kind at all -> a plain script dir.
8424
+ # The build-ish regex is used as an EXCLUSION so a build hidden under a
8425
+ # non-"build" script name (compile/dist/...) does NOT misfire N/A.
8426
+ local has_foreign_manifest="false"
8427
+ if [ -f "$tree/go.mod" ] || [ -f "$tree/Cargo.toml" ] \
8428
+ || [ -f "$tree/Makefile" ] || [ -f "$tree/makefile" ] || [ -f "$tree/GNUmakefile" ] \
8429
+ || [ -f "$tree/Makefile.in" ] || [ -f "$tree/configure" ] || [ -f "$tree/configure.ac" ] || [ -f "$tree/configure.in" ] \
8430
+ || [ -f "$tree/CMakeLists.txt" ] || [ -f "$tree/meson.build" ] \
8431
+ || [ -f "$tree/pom.xml" ] || [ -f "$tree/build.xml" ] \
8432
+ || [ -f "$tree/build.gradle" ] || [ -f "$tree/build.gradle.kts" ] \
8433
+ || [ -f "$tree/settings.gradle" ] || [ -f "$tree/settings.gradle.kts" ] || [ -f "$tree/gradlew" ] \
8434
+ || [ -f "$tree/build.sbt" ] \
8435
+ || [ -f "$tree/WORKSPACE" ] || [ -f "$tree/WORKSPACE.bazel" ] || [ -f "$tree/MODULE.bazel" ] \
8436
+ || [ -f "$tree/setup.py" ] || [ -f "$tree/pyproject.toml" ] \
8437
+ || compgen -G "$tree/*.csproj" >/dev/null 2>&1 \
8438
+ || compgen -G "$tree/*.sln" >/dev/null 2>&1 \
8439
+ || compgen -G "$tree/*.fsproj" >/dev/null 2>&1; then
8440
+ has_foreign_manifest="true"
8441
+ fi
8442
+ # N/A fires on POSITIVE proof-of-no-build, which we can only assert for a
8443
+ # package.json project: it EXISTS and its scripts are build-ish-free and no
8444
+ # foreign manifest / build-tool devDep is present -> a JS CLI/lib that
8445
+ # genuinely has no build step (the founder's invoice case). CRITICAL (the
8446
+ # council's convergence line): a project with NO package.json is "I don't
8447
+ # recognize a build here" = IGNORANCE, not proof-of-no-build. Ignorance must
8448
+ # map to not_run (honest gap), NEVER N/A -- else Zig/autotools/bare-C/meson/
8449
+ # bazel/anything-unborn silently reads VERIFIED. This makes the ENTIRE
8450
+ # no-package.json universe honest by CONSTRUCTION (list-free), which is why
8451
+ # this converges where four rounds of adding-to-a-list could not.
8452
+ if [ "$has_foreign_manifest" = "false" ] && [ -f "$tree/package.json" ]; then
8453
+ local has_build_devdep="false"
8454
+ # A build TOOL as a (dev)dependency means a build exists even if it runs
8455
+ # under a non-"build" script name -> stay not_run, do not claim N/A.
8456
+ if grep -qE '"(vite|webpack|rollup|esbuild|parcel|typescript|tsc|@swc/core|turbopack|rspack|tsup|microbundle)"[[:space:]]*:' "$tree/package.json" 2>/dev/null; then
8457
+ has_build_devdep="true"
8458
+ fi
8459
+ if [ "$has_build_devdep" = "false" ] \
8460
+ && ! grep -qE '"(build|compile|dist|bundle|webpack|vite|tsc|rollup|esbuild|prepare|prepack)"[[:space:]]*:' "$tree/package.json" 2>/dev/null; then
8461
+ applicable="false"; build_class="none"
8462
+ fi
8463
+ # else: a build-ish script or a build-tool devDep we don't auto-run ->
8464
+ # stays not_run (an honest gap). Known bounded edge: a polyglot repo with
8465
+ # a package.json (no build) co-present with an UNLISTED foreign build
8466
+ # manifest could read N/A; not common and not list-free-fixable, so it is
8467
+ # a documented CONCERN, not a blocker.
8468
+ fi
8469
+ # No package.json (foreign or not) -> build_class stays "present" -> not_run.
8470
+ # has_foreign_manifest=true -> also not_run. Only the narrow package.json-
8471
+ # no-build case above reaches N/A.
8472
+ fi
8473
+
8474
+ if [ "$build_class" = "present" ]; then
8475
+ # A build phase exists but we did not run it -> honest not_run gap. applicable
8476
+ # stays true (a build IS applicable), status not_run (we did not verify it).
8477
+ applicable="true"; ran="false"; status="not_run"
8478
+ log_info "Build check: a build system is present but not auto-run -> honest gap (not verified)"
8479
+ elif [ "$applicable" = "true" ]; then
8480
+ # EXECUTION is expensive (a real vite/webpack/go/cargo build, seconds to
8481
+ # minutes) so we run it AT MOST ONCE per build run, not every iteration --
8482
+ # honoring the "fastest / lowest cost" goal. A freshness marker (mirrors the
8483
+ # test-results.iter pattern) records that the build already ran this run; a
8484
+ # later iteration reuses the recorded verified/failed status instead of
8485
+ # re-building. LOKI_BUILD_CHECK=0 opts out entirely (records N/A-style skip
8486
+ # without running). If a prior result exists and is still valid, keep it.
8487
+ local marker="$quality_dir/.build-check.done"
8488
+ if [ "${LOKI_BUILD_CHECK:-1}" = "0" ]; then
8489
+ log_info "Build check: execution disabled (LOKI_BUILD_CHECK=0); recording applicability only"
8490
+ ran="false"; exit_code="null"; status="not_run"
8491
+ elif [ -f "$marker" ] && [ -f "$out_file" ]; then
8492
+ log_info "Build check: already ran this build; reusing recorded result"
8493
+ return 0
8494
+ else
8495
+ local rc=0
8496
+ ( cd "$tree" && timeout "$timeout_s" sh -c "$cmd" >/dev/null 2>&1 ) || rc=$?
8497
+ ran="true"; exit_code="$rc"
8498
+ if [ "$rc" -eq 0 ]; then status="verified"; else status="failed"; fi
8499
+ : > "$marker" 2>/dev/null || true
8500
+ log_info "Build check: $cmd -> exit $rc"
8501
+ fi
8502
+ else
8503
+ # build_class="none": a POSITIVE proof-of-no-build determination -> honest
8504
+ # N/A (the founder's CLI). applicable already false; status not_applicable.
8505
+ applicable="false"; ran="false"; status="not_applicable"
8506
+ log_info "Build check: no build step for this stack (N/A)"
8507
+ fi
8508
+
8509
+ printf '{"timestamp":"%s","command":"%s","ran":%s,"applicable":%s,"exit_code":%s,"duration_sec":null,"status":"%s"}\n' \
8510
+ "$ts" "$cmd" "$ran" "$applicable" "$exit_code" "$status" > "$out_file"
8511
+ return 0
8512
+ }
8513
+
8357
8514
  enforce_static_analysis() {
8358
8515
  local loki_dir="${TARGET_DIR:-.}/.loki"
8359
8516
  local quality_dir="$loki_dir/quality"
@@ -17574,6 +17731,14 @@ if __name__ == "__main__":
17574
17731
  fi
17575
17732
  emit_stage_complete "static_analysis" "$_stg_ok" "$_stg_t0"
17576
17733
  fi
17734
+ # Build check (#47). Records .loki/quality/build-results.json each
17735
+ # iteration so the Evidence Receipt tells the truth about the build:
17736
+ # a real build that ran (verified/failed) or an HONEST N/A when the
17737
+ # stack has no build step. Advisory (best-effort): a build failure
17738
+ # surfaces as a receipt gap via facts.build, never a hard loop block,
17739
+ # mirroring the security scan. Absent writer historically = facts.build
17740
+ # permanently not_run for every project (the founder-reported defect).
17741
+ enforce_build_check || true
17577
17742
  # Secure-by-default scan (v7.87.0). Advisory by default (never
17578
17743
  # blocks); records .loki/quality/security-findings.json each
17579
17744
  # iteration. Blocks only on un-waived HIGH when LOKI_SECURE_GATE=block.
@@ -7,7 +7,7 @@ Modules:
7
7
  control: Session control API (start/stop/pause/resume)
8
8
  """
9
9
 
10
- __version__ = "7.118.0"
10
+ __version__ = "7.119.0"
11
11
 
12
12
  # Expose the control app for easy import
13
13
  try:
@@ -0,0 +1,79 @@
1
+ # Evidence Receipt: honest build applicability (done once, for all customers)
2
+
3
+ ## The defect (founder-reported, 2026-07-03)
4
+
5
+ A sophisticated user built a Node CLI (invoice tool) and saw the Evidence Receipt say
6
+ "Build: not run - build not run", "Live health check: not captured", "No screenshot",
7
+ headline "Working, with gaps". He concluded *nothing was validated* -- and that read is the
8
+ bug: it destroys trust in genuinely-validated work.
9
+
10
+ ## Ground truth (from the persisted proof of run-20260703034719)
11
+
12
+ - `facts.tests` = `verified`, exit 0 -- tests GENUINELY ran and passed.
13
+ - `facts.security` = `ran:true, clean` -- security GENUINELY ran, real clean scan.
14
+ - `facts.build` = `ran:false, status:not_run, command:""` -- and this is counted as a GAP
15
+ by `_compute_degraded` (proof-generator.py:903-908), which forces "WITH GAPS".
16
+ - `facts.quality_gates` = `[]` (EMPTY) -- verify.sh's deterministic build gate does NOT
17
+ reach the SaaS proof.
18
+
19
+ ## Root cause (systemic, every build, every customer)
20
+
21
+ `build-results.json` has **NO writer**. `_collect_build` (proof-generator.py:319) reads
22
+ `.loki/quality/build-results.json`, which nothing ever writes, so `facts.build` defaults to
23
+ `not_run` (line 333) for EVERY build. The sibling collectors DO have writers in run.sh
24
+ (`enforce_static_analysis` 8357, `run_secure_scan` 8720, `enforce_test_coverage` 9170 ->
25
+ test-results.json / security-findings.json / static-analysis.json). Build was never wired.
26
+
27
+ So "Build: not run" is not a per-project decision -- it is a permanent, structural
28
+ mislabel. A build that has no build step (a CLI) and a build that genuinely skipped a real
29
+ build both read identically as "not run" and both count as a gap.
30
+
31
+ ## The fix (honest, no fabrication, no mocking -- the founder's hard constraint)
32
+
33
+ Add the missing writer as a sibling collector, with a POSITIVE applicability determination:
34
+
35
+ 1. **run.sh `enforce_build_check()`** (new, sibling to enforce_static_analysis): detect the
36
+ stack's build command (npm "build" script / go build / cargo build -- same detectors as
37
+ verify.sh:250-291). Then:
38
+ - build command exists -> RUN it -> record `{ran:true, command, exit_code, status:
39
+ verified|failed}`.
40
+ - genuinely NO build step for this stack -> record `{ran:false, applicable:false,
41
+ status:not_applicable, command:""}`. This is a POSITIVE "no build phase" signal, not an
42
+ absent file.
43
+ Write `.loki/quality/build-results.json`. Call it where the sibling collectors are called.
44
+
45
+ 2. **proof-generator.py `_collect_build`**: pass through `applicable:false` -> status
46
+ `not_applicable`. CRITICAL: `not_applicable` ONLY from an explicit `applicable:false` in
47
+ the file. File ABSENT or unknown status -> `not_run` (honest gap), NEVER N/A. Absent must
48
+ never mean N/A (that would flip un-built projects green -- fake-green).
49
+
50
+ 3. **proof-generator.py `_compute_degraded`**: `not_applicable` is NOT a gap (excluded from
51
+ the weak set for build). A failed/skipped/not_run build stays a gap. Mirror-image guard:
52
+ a real build script that FAILS still emits `failed` -> gap -> never green.
53
+
54
+ 4. **proof-generator.py status normalizer (line 215)**: `not_applicable` passes through.
55
+
56
+ 5. **SPA adapter.ts**: `not_applicable` renders "N/A - no build step for this stack" (a
57
+ neutral/pass tier, NOT a warn/gap), distinct from "not run".
58
+
59
+ ## Anti-fake-green invariants (the trust moat)
60
+
61
+ - N/A ONLY on positive `applicable:false`. Absent file / unknown status -> honest gap.
62
+ - A build script that got skipped or failed STILL shows a gap and CANNOT go green.
63
+ - The directional regression test (write FIRST): Node project WITH a build script whose
64
+ build FAILS -> `facts.build=failed` -> degraded -> headline NOT green. And: build gate
65
+ MISSING -> still a gap, not N/A.
66
+ - N/A does not gate the seal any more than a gap does; it is honest applicability, not a pass.
67
+
68
+ ## Measurable before/after
69
+
70
+ Before: invoice CLI -> "Build: not run", headline "Working, with gaps".
71
+ After: fresh invoice CLI build -> "Build: N/A (no build step for this stack)", tests passed,
72
+ security scanned-clean, headline VERIFIED (no un-closed applicable gaps).
73
+
74
+ ## Constraints
75
+
76
+ Verdict-core: council 3/3 + local-ci + 14 version locations. Verify via
77
+ function-extraction/golden harness -- NEVER run the engine build from the worktree. Run the
78
+ EXISTING tests/test_proof_generator.py green before AND after (it has build-results.json
79
+ fixtures that this change touches). Deploy to live SaaS is `bun install -g loki-mode@<ver>`.
@@ -2,7 +2,7 @@
2
2
 
3
3
  The flagship product of [Autonomi](https://www.autonomi.dev/). Loki Mode is a spec-driven autonomous builder with a built-in trust layer that takes any spec to a deployed product and verifies completion with evidence (quality gates plus a completion council), not just a "done" claim. Complete installation instructions for all platforms and use cases.
4
4
 
5
- **Version:** v7.118.0
5
+ **Version:** v7.119.0
6
6
 
7
7
  ---
8
8
 
@@ -1,5 +1,5 @@
1
1
  // @bun
2
- var q8=Object.defineProperty;var J8=($)=>$;function V8($,Q){this[$]=J8.bind(null,Q)}var b=($,Q)=>{for(var Z in Q)q8($,Z,{get:Q[Z],enumerable:!0,configurable:!0,set:V8.bind(Q,Z)})};var P=($,Q)=>()=>($&&(Q=$($=0)),Q);var J$=import.meta.require;var m1={};b(m1,{lokiDir:()=>j,homeLokiDir:()=>T$,findRepoRootForVersion:()=>$1,REPO_ROOT:()=>h});import{resolve as t,dirname as e$}from"path";import{fileURLToPath as W8}from"url";import{existsSync as N$}from"fs";import{homedir as H8}from"os";function G8(){let $=v1;for(let Q=0;Q<6;Q++){if(N$(t($,"VERSION"))&&N$(t($,"autonomy/run.sh")))return $;let Z=e$($);if(Z===$)break;$=Z}return t(v1,"..","..","..")}function $1($){let Q=$;for(let Z=0;Z<6;Z++){if(N$(t(Q,"VERSION"))&&N$(t(Q,"autonomy/run.sh")))return Q;let z=e$(Q);if(z===Q)break;Q=z}return t($,"..","..","..")}function j(){return process.env.LOKI_DIR??t(process.cwd(),".loki")}function T$(){return t(H8(),".loki")}var v1,h;var C=P(()=>{v1=e$(W8(import.meta.url));h=G8()});import{readFileSync as U8}from"fs";import{resolve as Y8,dirname as B8}from"path";import{fileURLToPath as M8}from"url";function S$(){if(Q$!==null)return Q$;let $="7.118.0";if(typeof $==="string"&&$.length>0)return Q$=$,Q$;try{let Q=B8(M8(import.meta.url)),Z=$1(Q);Q$=U8(Y8(Z,"VERSION"),"utf-8").trim()}catch{Q$="unknown"}return Q$}var Q$=null;var Q1=P(()=>{C()});var p1={};b(p1,{runOrThrow:()=>S8,run:()=>R,readStreamCapped:()=>c1,commandVersion:()=>C8,commandExists:()=>u,ShellError:()=>Z1,MAX_STDOUT_BYTES:()=>u1});async function c1($,Q=u1){let Z=$.getReader(),z=new TextDecoder,X="",q=0;try{while(q<Q){let{done:K,value:W}=await Z.read();if(K)break;if(!W)continue;if(q+=W.byteLength,q>Q){let V=W.byteLength-(q-Q);X+=z.decode(W.subarray(0,V),{stream:!0});break}X+=z.decode(W,{stream:!0})}X+=z.decode()}finally{try{await Z.cancel()}catch{}Z.releaseLock()}return X}async function R($,Q={}){let Z=Bun.spawn({cmd:[...$],stdout:"pipe",stderr:"pipe",env:Q.env?{...process.env,...Q.env}:process.env,cwd:Q.cwd}),z,X;if(Q.timeoutMs&&Q.timeoutMs>0)z=setTimeout(()=>{try{Z.kill("SIGTERM")}catch{}X=setTimeout(()=>{try{Z.kill("SIGKILL")}catch{}},2000)},Q.timeoutMs);try{let[q,K,W]=await Promise.all([c1(Z.stdout),new Response(Z.stderr).text(),Z.exited]);return{stdout:q,stderr:K,exitCode:W}}finally{if(z)clearTimeout(z);if(X)clearTimeout(X)}}async function S8($,Q={}){let Z=await R($,Q);if(Z.exitCode!==0)throw new Z1(`command failed (${Z.exitCode}): ${$.join(" ")}`,Z.exitCode,Z.stdout,Z.stderr);return Z}async function u($){let Q=D8($),Z=await R(["sh","-c",`command -v ${Q}`],{timeoutMs:5000});if(Z.exitCode===0)return Z.stdout.trim()||null;return null}function D8($){if(!/^[A-Za-z0-9._/-]+$/.test($))throw Error(`refused to shell-escape suspect token: ${$}`);return $}async function C8($,Q="--version"){if(!await u($))return null;let z=await R([$,Q],{timeoutMs:5000});if(z.exitCode!==0)return null;return((z.stdout||z.stderr).split(/\r?\n/)[0]?.trim()??"")||null}var u1=16777216,Z1;var o=P(()=>{Z1=class Z1 extends Error{message;exitCode;stdout;stderr;constructor($,Q,Z,z){super($);this.message=$;this.exitCode=Q;this.stdout=Z;this.stderr=z;this.name="ShellError"}}});function r($){return b8?"":$}var b8,M,S,_,tZ,L,k,y,J;var p=P(()=>{b8=(process.env.NO_COLOR??"").length>0;M=r("\x1B[0;31m"),S=r("\x1B[0;32m"),_=r("\x1B[1;33m"),tZ=r("\x1B[0;34m"),L=r("\x1B[0;36m"),k=r("\x1B[1m"),y=r("\x1B[2m"),J=r("\x1B[0m")});import{existsSync as l8}from"fs";async function Z$(){if(A$!==void 0)return A$;let $="/opt/homebrew/bin/python3.12";if(l8($))return A$=$,$;let Q=await u("python3.12");if(Q)return A$=Q,Q;let Z=await u("python3");return A$=Z,Z}async function z$($,Q={}){let Z=await Z$();if(!Z)return{stdout:"",stderr:"python3 not found",exitCode:127};return R([Z,"-c",$],Q)}var A$;var V$=P(()=>{o()});var V0={};b(V0,{runStatus:()=>U3});import{existsSync as v,readFileSync as H$,readdirSync as $0,statSync as Q0}from"fs";import{resolve as D,basename as z3}from"path";import{homedir as X3}from"os";function Z0($){let Q=Math.trunc($);if(Q>=1e6)return`${(Math.trunc(Q/1e6*10)/10).toFixed(1)}M`;if(Q>=1000)return`${(Math.trunc(Q/1000*10)/10).toFixed(1)}K`;return String(Q)}function z0($,Q,Z){if(Q===0)return null;let z=Math.trunc($*100/Q),X=Math.trunc($*C$/Q);if(X>C$)X=C$;let q=C$-X,K=S;if(z>=80)K=M;else if(z>=50)K=_;let W="=".repeat(Math.max(0,X))+" ".repeat(Math.max(0,q)),V=Z0($),H=Z0(Q);return` ${k}${Z}${J} ${K}[${W}]${J} ${z}% (${V} / ${H})`}async function q3(){if(await u("jq"))return!0;return process.stdout.write(`${M}Error: jq is required but not installed.${J}
2
+ var q8=Object.defineProperty;var J8=($)=>$;function V8($,Q){this[$]=J8.bind(null,Q)}var b=($,Q)=>{for(var Z in Q)q8($,Z,{get:Q[Z],enumerable:!0,configurable:!0,set:V8.bind(Q,Z)})};var P=($,Q)=>()=>($&&(Q=$($=0)),Q);var J$=import.meta.require;var m1={};b(m1,{lokiDir:()=>j,homeLokiDir:()=>T$,findRepoRootForVersion:()=>$1,REPO_ROOT:()=>h});import{resolve as t,dirname as e$}from"path";import{fileURLToPath as W8}from"url";import{existsSync as N$}from"fs";import{homedir as H8}from"os";function G8(){let $=v1;for(let Q=0;Q<6;Q++){if(N$(t($,"VERSION"))&&N$(t($,"autonomy/run.sh")))return $;let Z=e$($);if(Z===$)break;$=Z}return t(v1,"..","..","..")}function $1($){let Q=$;for(let Z=0;Z<6;Z++){if(N$(t(Q,"VERSION"))&&N$(t(Q,"autonomy/run.sh")))return Q;let z=e$(Q);if(z===Q)break;Q=z}return t($,"..","..","..")}function j(){return process.env.LOKI_DIR??t(process.cwd(),".loki")}function T$(){return t(H8(),".loki")}var v1,h;var C=P(()=>{v1=e$(W8(import.meta.url));h=G8()});import{readFileSync as U8}from"fs";import{resolve as Y8,dirname as B8}from"path";import{fileURLToPath as M8}from"url";function S$(){if(Q$!==null)return Q$;let $="7.119.0";if(typeof $==="string"&&$.length>0)return Q$=$,Q$;try{let Q=B8(M8(import.meta.url)),Z=$1(Q);Q$=U8(Y8(Z,"VERSION"),"utf-8").trim()}catch{Q$="unknown"}return Q$}var Q$=null;var Q1=P(()=>{C()});var p1={};b(p1,{runOrThrow:()=>S8,run:()=>R,readStreamCapped:()=>c1,commandVersion:()=>C8,commandExists:()=>u,ShellError:()=>Z1,MAX_STDOUT_BYTES:()=>u1});async function c1($,Q=u1){let Z=$.getReader(),z=new TextDecoder,X="",q=0;try{while(q<Q){let{done:K,value:W}=await Z.read();if(K)break;if(!W)continue;if(q+=W.byteLength,q>Q){let V=W.byteLength-(q-Q);X+=z.decode(W.subarray(0,V),{stream:!0});break}X+=z.decode(W,{stream:!0})}X+=z.decode()}finally{try{await Z.cancel()}catch{}Z.releaseLock()}return X}async function R($,Q={}){let Z=Bun.spawn({cmd:[...$],stdout:"pipe",stderr:"pipe",env:Q.env?{...process.env,...Q.env}:process.env,cwd:Q.cwd}),z,X;if(Q.timeoutMs&&Q.timeoutMs>0)z=setTimeout(()=>{try{Z.kill("SIGTERM")}catch{}X=setTimeout(()=>{try{Z.kill("SIGKILL")}catch{}},2000)},Q.timeoutMs);try{let[q,K,W]=await Promise.all([c1(Z.stdout),new Response(Z.stderr).text(),Z.exited]);return{stdout:q,stderr:K,exitCode:W}}finally{if(z)clearTimeout(z);if(X)clearTimeout(X)}}async function S8($,Q={}){let Z=await R($,Q);if(Z.exitCode!==0)throw new Z1(`command failed (${Z.exitCode}): ${$.join(" ")}`,Z.exitCode,Z.stdout,Z.stderr);return Z}async function u($){let Q=D8($),Z=await R(["sh","-c",`command -v ${Q}`],{timeoutMs:5000});if(Z.exitCode===0)return Z.stdout.trim()||null;return null}function D8($){if(!/^[A-Za-z0-9._/-]+$/.test($))throw Error(`refused to shell-escape suspect token: ${$}`);return $}async function C8($,Q="--version"){if(!await u($))return null;let z=await R([$,Q],{timeoutMs:5000});if(z.exitCode!==0)return null;return((z.stdout||z.stderr).split(/\r?\n/)[0]?.trim()??"")||null}var u1=16777216,Z1;var o=P(()=>{Z1=class Z1 extends Error{message;exitCode;stdout;stderr;constructor($,Q,Z,z){super($);this.message=$;this.exitCode=Q;this.stdout=Z;this.stderr=z;this.name="ShellError"}}});function r($){return b8?"":$}var b8,M,S,_,tZ,L,k,y,J;var p=P(()=>{b8=(process.env.NO_COLOR??"").length>0;M=r("\x1B[0;31m"),S=r("\x1B[0;32m"),_=r("\x1B[1;33m"),tZ=r("\x1B[0;34m"),L=r("\x1B[0;36m"),k=r("\x1B[1m"),y=r("\x1B[2m"),J=r("\x1B[0m")});import{existsSync as l8}from"fs";async function Z$(){if(A$!==void 0)return A$;let $="/opt/homebrew/bin/python3.12";if(l8($))return A$=$,$;let Q=await u("python3.12");if(Q)return A$=Q,Q;let Z=await u("python3");return A$=Z,Z}async function z$($,Q={}){let Z=await Z$();if(!Z)return{stdout:"",stderr:"python3 not found",exitCode:127};return R([Z,"-c",$],Q)}var A$;var V$=P(()=>{o()});var V0={};b(V0,{runStatus:()=>U3});import{existsSync as v,readFileSync as H$,readdirSync as $0,statSync as Q0}from"fs";import{resolve as D,basename as z3}from"path";import{homedir as X3}from"os";function Z0($){let Q=Math.trunc($);if(Q>=1e6)return`${(Math.trunc(Q/1e6*10)/10).toFixed(1)}M`;if(Q>=1000)return`${(Math.trunc(Q/1000*10)/10).toFixed(1)}K`;return String(Q)}function z0($,Q,Z){if(Q===0)return null;let z=Math.trunc($*100/Q),X=Math.trunc($*C$/Q);if(X>C$)X=C$;let q=C$-X,K=S;if(z>=80)K=M;else if(z>=50)K=_;let W="=".repeat(Math.max(0,X))+" ".repeat(Math.max(0,q)),V=Z0($),H=Z0(Q);return` ${k}${Z}${J} ${K}[${W}]${J} ${z}% (${V} / ${H})`}async function q3(){if(await u("jq"))return!0;return process.stdout.write(`${M}Error: jq is required but not installed.${J}
3
3
  `),process.stdout.write(`Install with:
4
4
  `),process.stdout.write(` brew install jq (macOS)
5
5
  `),process.stdout.write(` apt install jq (Debian/Ubuntu)
@@ -814,4 +814,4 @@ Set LOKI_LEGACY_BASH=1 to force the bash CLI for every command.
814
814
  `),2}default:return process.stderr.write(`Unknown command: ${Q}
815
815
  `),process.stderr.write(K8),2}}e1();process.on("SIGINT",()=>process.exit(130));process.on("SIGTERM",()=>process.exit(143));var SZ=await NZ(Bun.argv.slice(2));process.exit(SZ);
816
816
 
817
- //# debugId=01D367D3C33A5E7664756E2164756E21
817
+ //# debugId=7B2014E7E7C6AC4464756E2164756E21
package/mcp/__init__.py CHANGED
@@ -57,4 +57,4 @@ try:
57
57
  except ImportError:
58
58
  __all__ = ['mcp']
59
59
 
60
- __version__ = '7.118.0'
60
+ __version__ = '7.119.0'
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "loki-mode",
3
3
  "mcpName": "io.github.asklokesh/loki-mode",
4
- "version": "7.118.0",
4
+ "version": "7.119.0",
5
5
  "description": "Loki Mode by Autonomi. Autonomous spec-to-product system: takes a PRD, GitHub issue, OpenAPI/JSON/YAML, or one-line brief to a deployed app via the RARV-C closure loop with 8 quality gates. Provider-agnostic (Claude Code, OpenAI Codex, Cline, Aider).",
6
6
  "keywords": [
7
7
  "agent",
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
3
3
  "name": "loki-mode",
4
4
  "displayName": "Loki Mode",
5
- "version": "7.118.0",
5
+ "version": "7.119.0",
6
6
  "description": "Autonomous spec-to-product build system with a built-in trust layer (RARV-C closure loop, 8 quality gates, completion council). Ships Loki's spec-hardening, drift-detection, and deterministic PR verification commands plus the Loki MCP server.",
7
7
  "author": {
8
8
  "name": "Autonomi",