loki-mode 11.45.1 → 11.46.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/dashboard/__init__.py +1 -1
- package/docs/CLI-REFERENCE.md +1 -1
- package/docs/INSTALLATION.md +1 -1
- package/loki-ts/dist/loki.js +2 -2
- package/mcp/__init__.py +1 -1
- package/memory/embeddings.py +61 -7
- package/memory/vector_index.py +58 -12
- package/package.json +2 -2
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/web-app/dist/assets/{AdminPage-CKGu6MDY.js → AdminPage-Cpk2EHRn.js} +1 -1
- package/web-app/dist/assets/{Avatar-DjAsqby3.js → Avatar-xfdA6HHw.js} +1 -1
- package/web-app/dist/assets/{Badge-D5s_eUjs.js → Badge-BxcMTvOK.js} +1 -1
- package/web-app/dist/assets/{Button-CYZoRIOH.js → Button-BDJQTeBq.js} +1 -1
- package/web-app/dist/assets/{CockpitPage-Cqdp9xwf.js → CockpitPage-BRPsFxNM.js} +1 -1
- package/web-app/dist/assets/{ComparePage-CJjNv8K-.js → ComparePage-es4wlPFZ.js} +1 -1
- package/web-app/dist/assets/{ErrorBoundary-CA4Pa5r4.js → ErrorBoundary-BGAlBzcB.js} +1 -1
- package/web-app/dist/assets/{EvidenceReceiptPanel-CGIK2BN5.js → EvidenceReceiptPanel-CulRYQ28.js} +1 -1
- package/web-app/dist/assets/{GitHubIssuesPanel-DuKkuySj.js → GitHubIssuesPanel-DmDiKTZI.js} +1 -1
- package/web-app/dist/assets/{GitHubPRsPanel-BRX6ENsQ.js → GitHubPRsPanel-pibUi3FE.js} +1 -1
- package/web-app/dist/assets/{HomePage-ChPpzMJ3.js → HomePage-BTgWVuvl.js} +2 -2
- package/web-app/dist/assets/{LoginPage-BWA__z9w.js → LoginPage-CLVQjlQ-.js} +1 -1
- package/web-app/dist/assets/{MagicPage-BSuOaBVM.js → MagicPage-CuPYa26V.js} +1 -1
- package/web-app/dist/assets/{MetricsPage-DlsJH6AR.js → MetricsPage-BI01kRI4.js} +1 -1
- package/web-app/dist/assets/{NotFoundPage-Dds7yseD.js → NotFoundPage-BwS_zmkd.js} +1 -1
- package/web-app/dist/assets/{ProjectPage-BSro-U_S.js → ProjectPage-pGURtMmr.js} +3 -3
- package/web-app/dist/assets/{ProjectsPage-B1DEpZNU.js → ProjectsPage-Bjb4ecz5.js} +1 -1
- package/web-app/dist/assets/{SettingsPage-CwTg8Wjt.js → SettingsPage-DgkXJY8G.js} +1 -1
- package/web-app/dist/assets/{ShowcasePage-CzTfdzyL.js → ShowcasePage-W1kn0K8X.js} +1 -1
- package/web-app/dist/assets/{SystemSettingsPage-CcejpUpc.js → SystemSettingsPage-CVtV225z.js} +1 -1
- package/web-app/dist/assets/{TeamsPage-DwGaiWl_.js → TeamsPage-d_Yr3NNM.js} +1 -1
- package/web-app/dist/assets/{TemplatesPage-sMy0VQmd.js → TemplatesPage--P3OcRWw.js} +1 -1
- package/web-app/dist/assets/{TerminalOutput-rGSOZgkI.js → TerminalOutput-BzanuL3R.js} +1 -1
- package/web-app/dist/assets/{activity-Bz9ZprPj.js → activity-onNTo3z1.js} +1 -1
- package/web-app/dist/assets/{bell-C6hHKszJ.js → bell-DjZb8wxS.js} +1 -1
- package/web-app/dist/assets/{bot-Ck_DVuFs.js → bot-DC-zqs6V.js} +1 -1
- package/web-app/dist/assets/{check-D_M3QJOp.js → check-_TVDwdrq.js} +1 -1
- package/web-app/dist/assets/{chevron-left-f3ouHCeO.js → chevron-left-D8M7-5Kc.js} +1 -1
- package/web-app/dist/assets/{circle-alert-DD3Z-nGb.js → circle-alert-HUO4WzPf.js} +1 -1
- package/web-app/dist/assets/{clock-DdjEs6y1.js → clock-W2kDTGYx.js} +1 -1
- package/web-app/dist/assets/{cloud-D1zNol70.js → cloud-CswIXQ44.js} +1 -1
- package/web-app/dist/assets/{code-xml-Bk5yFRHa.js → code-xml-D2IospVb.js} +1 -1
- package/web-app/dist/assets/{database-BXEKYWVd.js → database-Dg9kxuUW.js} +1 -1
- package/web-app/dist/assets/{dollar-sign-COdqX73C.js → dollar-sign-Be49Rzh5.js} +1 -1
- package/web-app/dist/assets/{file-code-corner-BqwN-CPO.js → file-code-corner-BWmgmYUT.js} +1 -1
- package/web-app/dist/assets/{file-plus-BE2zGZdY.js → file-plus-Dv3GsHfI.js} +1 -1
- package/web-app/dist/assets/{globe-CfPl-m21.js → globe-mb1Su4WH.js} +1 -1
- package/web-app/dist/assets/{hammer-DZfFznI_.js → hammer-D1MoKYJh.js} +1 -1
- package/web-app/dist/assets/{index-C2ryWVlq.js → index-CjeJkKHf.js} +3 -3
- package/web-app/dist/assets/{layers-COVYBIgt.js → layers-Dw0b7-9N.js} +1 -1
- package/web-app/dist/assets/{loader-circle-Cr5ANGy4.js → loader-circle-DZFGHRZb.js} +1 -1
- package/web-app/dist/assets/{lock-BM8zkOYQ.js → lock-DyfnnkPv.js} +1 -1
- package/web-app/dist/assets/{package-FK3iVR80.js → package-CFhqaw7T.js} +1 -1
- package/web-app/dist/assets/{plus-CP8VeWSZ.js → plus-BGJd8wWM.js} +1 -1
- package/web-app/dist/assets/{refresh-cw-Cig4UX1f.js → refresh-cw-B-eHLtrF.js} +1 -1
- package/web-app/dist/assets/{rotate-ccw-DotJT86J.js → rotate-ccw-CZDw8m--.js} +1 -1
- package/web-app/dist/assets/{scroll-text-bV0sz1VB.js → scroll-text-BfFjI8cR.js} +1 -1
- package/web-app/dist/assets/{server-yfMjCTDd.js → server-C21JkB7U.js} +1 -1
- package/web-app/dist/assets/{shield-alert-CTNSlybB.js → shield-alert-Bojfzk9R.js} +1 -1
- package/web-app/dist/assets/{thumbs-up-C_xY1ipb.js → thumbs-up-BsB7OQxT.js} +1 -1
- package/web-app/dist/assets/{trash-2-Ch_SWgcL.js → trash-2-CvOAbh9v.js} +1 -1
- package/web-app/dist/assets/{trending-down-Hj94T7pm.js → trending-down-_lZH3kDf.js} +1 -1
- package/web-app/dist/assets/{trending-up-Bl3J70sK.js → trending-up-Bqln1HBv.js} +1 -1
- package/web-app/dist/assets/{upload-B_LNBIsG.js → upload-CNpkqzkA.js} +1 -1
- package/web-app/dist/assets/{usePolling-BxLm_OyJ.js → usePolling-D3dvIVbM.js} +1 -1
- package/web-app/dist/assets/{user-QLxP_azx.js → user-BhFi92qW.js} +1 -1
- package/web-app/dist/index.html +1 -1
package/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: loki-mode
|
|
|
3
3
|
description: Runs an autonomous software factory that knows what it is supposed to deliver and proves it did, with a signed receipt. Use when the user says Loki Mode or asks to build, fix or verify software autonomously.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Loki Mode v11.
|
|
6
|
+
# Loki Mode v11.46.0
|
|
7
7
|
|
|
8
8
|
**Current entry points (Loki 10 engine):** `loki "<task>"`, `loki owner/repo#N` and `loki quick "<task>"` run the Loki 10 engine and end with a signed receipt (`loki verify`). `loki backlog owner/repo --all` runs many issues in parallel. Guide: `docs/v10/GUIDE.md`. The skill instructions below, and `loki start`, describe the previous bash loop. PRD-file starts (`loki start ./prd.md`) and the opencode provider still run on it until FC38-SWEEP ports them; the legacy-engine command and the LOKI_ENGINE switch remain removed. Prefer `loki owner/repo#N` for issues.
|
|
9
9
|
|
|
@@ -476,4 +476,4 @@ Implemented, planned and deprecated items, with the version each landed in: `ski
|
|
|
476
476
|
|
|
477
477
|
---
|
|
478
478
|
|
|
479
|
-
**v11.
|
|
479
|
+
**v11.46.0 | [Autonomi](https://www.autonomi.dev/) flagship product | core skill**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
11.
|
|
1
|
+
11.46.0
|
package/dashboard/__init__.py
CHANGED
package/docs/CLI-REFERENCE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# CLI reference
|
|
2
2
|
|
|
3
|
-
Generated from `loki-ts/src/cli/registry.ts` by `scripts/generate-stale-zero.sh` for v11.
|
|
3
|
+
Generated from `loki-ts/src/cli/registry.ts` by `scripts/generate-stale-zero.sh` for v11.46.0. Do not edit by hand.
|
|
4
4
|
Hidden and legacy-only commands are omitted; see `docs/v10/CLI-MODERN.md` for the full inventory.
|
|
5
5
|
|
|
6
6
|
| Command | Description |
|
package/docs/INSTALLATION.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Loki Mode, by [Autonomi](https://www.autonomi.dev/), turns a spec or an issue into a verified pull request with a receipt you can check. This page covers installing it, a first run, and the options around it.
|
|
4
4
|
|
|
5
|
-
**Version:** v11.
|
|
5
|
+
**Version:** v11.46.0
|
|
6
6
|
|
|
7
7
|
**Engine note:** `loki start` is the primary command. `loki start`, `loki "<task>"`, `loki owner/repo#N` and `loki quick` all run the Loki 10 engine, whatever the flag order or input form (PRD file, issue ref, task or one-word brief). The previous loop runs only on `--engine legacy`, `LOKI_ENGINE=legacy`, or for one call when a flag Loki 10 cannot honor is present. See the [user guide](v10/GUIDE.md) and the [5-minute quickstart](QUICKSTART.md).
|
|
8
8
|
|
package/loki-ts/dist/loki.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var _b0=Object.create;var{getPrototypeOf:kb0,defineProperty:CK,getOwnPropertyNames:zo,getOwnPropertyDescriptor:xb0}=Object,Wo=Object.prototype.hasOwnProperty;function Ko(Z){return this[Z]}var Sb0,yb0,bb0=(Z,$,J)=>{var X=Z!=null&&typeof Z==="object";if(X){var Y=$?Sb0??=new WeakMap:yb0??=new WeakMap,Q=Y.get(Z);if(Q)return Q}J=Z!=null?_b0(kb0(Z)):{};let z=$||!Z||!Z.__esModule?CK(J,"default",{value:Z,enumerable:!0}):J;for(let W of zo(Z))if(!Wo.call(z,W))CK(z,W,{get:Ko.bind(Z,W),enumerable:!0});if(X)Y.set(Z,z);return z},vb0=(Z)=>{var $=(Qo??=new WeakMap).get(Z),J;if($)return $;if($=CK({},"__esModule",{value:!0}),Z&&typeof Z==="object"||typeof Z==="function"){for(var X of zo(Z))if(!Wo.call($,X))CK($,X,{get:Ko.bind(Z,X),enumerable:!(J=xb0(Z,X))||J.enumerable})}return Qo.set(Z,$),$},Qo,lN=(Z,$)=>()=>($||Z(($={exports:{}}).exports,$),$.exports);var hb0=(Z)=>Z;function fb0(Z,$){this[Z]=hb0.bind(null,$)}var A0=(Z,$)=>{for(var J in $)CK(Z,J,{get:$[J],enumerable:!0,configurable:!0,set:fb0.bind($,J)})};var S=(Z,$)=>()=>(Z&&($=Z(Z=0)),$);var s9=import.meta.require;var Go={};A0(Go,{lokiDir:()=>P0,homeLokiDir:()=>B2,findRepoRootForVersion:()=>FK,REPO_ROOT:()=>C0});import{resolve as CZ,dirname as $E}from"path";import{fileURLToPath as gb0}from"url";import{existsSync as aN}from"fs";import{homedir as mb0}from"os";function ub0(){let Z=Vo;for(let $=0;$<6;$++){if(aN(CZ(Z,"VERSION"))&&aN(CZ(Z,"autonomy/run.sh")))return Z;let J=$E(Z);if(J===Z)break;Z=J}return CZ(Vo,"..","..","..")}function FK(Z){let $=Z;for(let J=0;J<6;J++){if(aN(CZ($,"VERSION"))&&aN(CZ($,"autonomy/run.sh")))return $;let X=$E($);if(X===$)break;$=X}return CZ(Z,"..","..","..")}function P0(){return process.env.LOKI_DIR??CZ(process.cwd(),".loki")}function B2(){return CZ(mb0(),".loki")}var Vo,C0;var n0=S(()=>{Vo=$E(gb0(import.meta.url));C0=ub0()});import{readFileSync as pb0}from"fs";import{resolve as cb0,dirname as db0}from"path";import{fileURLToPath as lb0}from"url";function q6(){if(w1!==null)return w1;let Z="11.
|
|
2
|
+
var _b0=Object.create;var{getPrototypeOf:kb0,defineProperty:CK,getOwnPropertyNames:zo,getOwnPropertyDescriptor:xb0}=Object,Wo=Object.prototype.hasOwnProperty;function Ko(Z){return this[Z]}var Sb0,yb0,bb0=(Z,$,J)=>{var X=Z!=null&&typeof Z==="object";if(X){var Y=$?Sb0??=new WeakMap:yb0??=new WeakMap,Q=Y.get(Z);if(Q)return Q}J=Z!=null?_b0(kb0(Z)):{};let z=$||!Z||!Z.__esModule?CK(J,"default",{value:Z,enumerable:!0}):J;for(let W of zo(Z))if(!Wo.call(z,W))CK(z,W,{get:Ko.bind(Z,W),enumerable:!0});if(X)Y.set(Z,z);return z},vb0=(Z)=>{var $=(Qo??=new WeakMap).get(Z),J;if($)return $;if($=CK({},"__esModule",{value:!0}),Z&&typeof Z==="object"||typeof Z==="function"){for(var X of zo(Z))if(!Wo.call($,X))CK($,X,{get:Ko.bind(Z,X),enumerable:!(J=xb0(Z,X))||J.enumerable})}return Qo.set(Z,$),$},Qo,lN=(Z,$)=>()=>($||Z(($={exports:{}}).exports,$),$.exports);var hb0=(Z)=>Z;function fb0(Z,$){this[Z]=hb0.bind(null,$)}var A0=(Z,$)=>{for(var J in $)CK(Z,J,{get:$[J],enumerable:!0,configurable:!0,set:fb0.bind($,J)})};var S=(Z,$)=>()=>(Z&&($=Z(Z=0)),$);var s9=import.meta.require;var Go={};A0(Go,{lokiDir:()=>P0,homeLokiDir:()=>B2,findRepoRootForVersion:()=>FK,REPO_ROOT:()=>C0});import{resolve as CZ,dirname as $E}from"path";import{fileURLToPath as gb0}from"url";import{existsSync as aN}from"fs";import{homedir as mb0}from"os";function ub0(){let Z=Vo;for(let $=0;$<6;$++){if(aN(CZ(Z,"VERSION"))&&aN(CZ(Z,"autonomy/run.sh")))return Z;let J=$E(Z);if(J===Z)break;Z=J}return CZ(Vo,"..","..","..")}function FK(Z){let $=Z;for(let J=0;J<6;J++){if(aN(CZ($,"VERSION"))&&aN(CZ($,"autonomy/run.sh")))return $;let X=$E($);if(X===$)break;$=X}return CZ(Z,"..","..","..")}function P0(){return process.env.LOKI_DIR??CZ(process.cwd(),".loki")}function B2(){return CZ(mb0(),".loki")}var Vo,C0;var n0=S(()=>{Vo=$E(gb0(import.meta.url));C0=ub0()});import{readFileSync as pb0}from"fs";import{resolve as cb0,dirname as db0}from"path";import{fileURLToPath as lb0}from"url";function q6(){if(w1!==null)return w1;let Z="11.46.0";if(typeof Z==="string"&&Z.length>0)return w1=Z,w1;try{let $=db0(lb0(import.meta.url)),J=FK($);w1=pb0(cb0(J,"VERSION"),"utf-8").trim()}catch{w1="unknown"}return w1}var w1=null;var FZ=S(()=>{n0()});import{mkdirSync as XE,readFileSync as iN,realpathSync as ab0,statSync as ib0,writeFileSync as YE}from"fs";import{dirname as YY,join as JE,resolve as Ho}from"path";function tb0(){return Ho(B2(),"cache","update-check.json")}function IZ(Z){let $=/^(\d+)\.(\d+)\.(\d+)$/.exec(Z.trim());if(!$)return null;return[Number($[1]),Number($[2]),Number($[3])]}function IK(Z,$){let J=IZ(Z),X=IZ($);if(!J||!X)return!1;let[Y,Q,z]=J,[W,K,V]=X;if(Y!==W)return Y>W;if(Q!==K)return Q>K;return z>V}function qo(){let Z=(process.env.LOKI_NO_UPDATE_CHECK??"").trim().toLowerCase();if(Z==="1"||Z==="true"||Z==="yes")return!0;if(process.env.CI)return!0;if(!process.stdout.isTTY)return!0;return!1}function Uo(Z){try{let $=iN(Z,"utf-8"),J=JSON.parse($);if(typeof J.checkedAt==="number"&&typeof J.latest==="string"&&IZ(J.latest)!==null)return{checkedAt:J.checkedAt,latest:J.latest}}catch{}return null}function eb0(Z){try{let $=JSON.parse(iN(Z,"utf-8")).failedAt;if(typeof $==="number")return $}catch{}return null}function Zv0(Z,$){let J=Uo(Z);try{XE(YY(Z),{recursive:!0}),YE(Z,JSON.stringify({...J??{},failedAt:$}),"utf-8")}catch{}}function $v0(Z,$){try{XE(YY(Z),{recursive:!0}),YE(Z,JSON.stringify($),"utf-8")}catch{}}async function Jv0(){try{let Z=await fetch(ob0,{signal:AbortSignal.timeout(sb0),headers:{accept:"application/json"}});if(!Z.ok)return null;let $=await Z.json();if(typeof $.version==="string"&&IZ($.version)!==null)return $.version}catch{}return null}async function Xv0(Z=Date.now(),$=Jv0,J=tb0()){let X=Uo(J);if(X&&Z-X.checkedAt<nb0)return X.latest;let Y=eb0(J);if(Y!==null&&Z-Y>=0&&Z-Y<rb0)return null;let Q=await $();if(Q===null)return Zv0(J,Z),null;return $v0(J,{checkedAt:Z,latest:Q}),Q}function Yv0(Z,$=process.env){if(IZ(Z)===null)return null;let X=$.PATH;if(!X)return null;let Y=new Set;for(let Q of X.split(":")){if(!Q)continue;let z=JE(Q,"loki"),W;try{ib0(z),W=ab0(z)}catch{continue}if(Y.has(W))continue;Y.add(W);try{let K=JE(YY(YY(W)),"package.json"),V=JSON.parse(iN(K,"utf8")).version;if(typeof V!=="string")continue;if(IK(V,Z))return{path:z,version:V}}catch{continue}}return null}function Qv0(){return Ho(B2(),"cache","last-seen-version.json")}function zv0(Z,$={}){try{if(qo())return!1;if(IZ(Z)===null)return!1;let J=$.seenFile??Qv0(),X=null;try{let Q=JSON.parse(iN(J,"utf-8")).version;if(typeof Q==="string"&&IZ(Q)!==null)X=Q}catch{}if(X!==null&&!IK(Z,X))return!1;try{XE(YY(J),{recursive:!0}),YE(J,JSON.stringify({version:Z}),"utf-8")}catch{return!1}if(X===null)return!1;return($.write??((Q)=>process.stderr.write(Q)))(`Loki Mode upgraded ${X} -> ${Z}. What is new: https://github.com/asklokesh/loki-mode/releases/tag/v${Z}
|
|
3
3
|
`),!0}catch{return!1}}function Wv0(Z){let $=Z.replace(/\\/g,"/");if($.includes("/Cellar/"))return"brew upgrade loki-mode";if(/\/pnpm\//.test($)||$.includes("/.pnpm/"))return"pnpm add -g loki-mode (or npm i -g loki-mode)";if($.includes("/yarn/global/")||$.includes("/.yarn/"))return"yarn global add loki-mode (or npm i -g loki-mode)";if($.includes("/.bun/"))return"bun install -g loki-mode (or npm i -g loki-mode)";if($.includes("/lib/node_modules/"))return"npm i -g loki-mode (or bun install -g loki-mode)";if($.includes("/homebrew/"))return"brew upgrade loki-mode";return"bun install -g loki-mode (or npm i -g loki-mode)"}async function Bo(Z,$={}){try{if(qo())return;if(IZ(Z)===null)return;let J=$.write??((Q)=>process.stderr.write(Q));zv0(Z,{write:J,...$.cacheFile?{seenFile:JE(YY($.cacheFile),"last-seen-version.json")}:{}});let X=Yv0(Z,$.env??process.env);if(X!==null){J(`Loki Mode ${X.version} is installed but not the one running (you are running ${Z}).
|
|
4
4
|
Another loki earlier on PATH is winning. Newer copy: ${X.path}
|
|
5
5
|
Run \`which -a loki\` to see the order, then remove or re-point the earlier entry.
|
|
@@ -3263,4 +3263,4 @@ Unknown commands exit 2 with a suggestion; run 'loki help' for the full list.
|
|
|
3263
3263
|
`);{let{suggestCommand:X}=await Promise.resolve().then(() => (Z4(),no)),Y=$===void 0?void 0:X($);if(Y)process.stderr.write(`Did you mean 'loki ${Y}'?
|
|
3264
3264
|
`)}return process.stderr.write(Ib0),2}}CF0();var Tb0=()=>globalThis[Symbol.for("loki.ownsStopSignals")]===!0;process.on("SIGINT",()=>{if(!Tb0())process.exit(130)});process.on("SIGTERM",()=>{if(!Tb0())process.exit(143)});var RU9=await PU9(Bun.argv.slice(2));process.exit(RU9);
|
|
3265
3265
|
|
|
3266
|
-
//# debugId=
|
|
3266
|
+
//# debugId=B9C6D431B8F4B35F0F13D1D88F070B41
|
package/mcp/__init__.py
CHANGED
package/memory/embeddings.py
CHANGED
|
@@ -86,6 +86,11 @@ class EmbeddingConfig:
|
|
|
86
86
|
|
|
87
87
|
# Dimension settings
|
|
88
88
|
dimension: int = 384 # Default for MiniLM-L6-v2
|
|
89
|
+
# Matryoshka-style truncation: keep the leading N components, then
|
|
90
|
+
# re-normalize. None keeps the provider's native dimension.
|
|
91
|
+
output_dimension: Optional[int] = None
|
|
92
|
+
# Storage dtype for a VectorIndex built from this config.
|
|
93
|
+
dtype: str = "float32"
|
|
89
94
|
|
|
90
95
|
# API keys (loaded from env if not provided)
|
|
91
96
|
openai_api_key: Optional[str] = None
|
|
@@ -175,6 +180,13 @@ class EmbeddingConfig:
|
|
|
175
180
|
if self.model in self.MODEL_DIMENSIONS:
|
|
176
181
|
self.dimension = self.MODEL_DIMENSIONS[self.model]
|
|
177
182
|
|
|
183
|
+
if self.output_dimension is not None and self.output_dimension < 1:
|
|
184
|
+
raise ValueError(
|
|
185
|
+
f"output_dimension must be a positive integer, got {self.output_dimension!r}"
|
|
186
|
+
)
|
|
187
|
+
if self.dtype not in ("float32", "float16"):
|
|
188
|
+
raise ValueError(f"dtype must be float32 or float16, got {self.dtype!r}")
|
|
189
|
+
|
|
178
190
|
@classmethod
|
|
179
191
|
def from_env(cls) -> "EmbeddingConfig":
|
|
180
192
|
"""Create config from environment variables."""
|
|
@@ -184,6 +196,9 @@ class EmbeddingConfig:
|
|
|
184
196
|
openai_api_key=os.environ.get("OPENAI_API_KEY"),
|
|
185
197
|
cohere_api_key=os.environ.get("COHERE_API_KEY"),
|
|
186
198
|
voyage_api_key=os.environ.get("VOYAGE_API_KEY"),
|
|
199
|
+
output_dimension=int(os.environ["LOKI_EMBEDDING_OUTPUT_DIMENSION"])
|
|
200
|
+
if os.environ.get("LOKI_EMBEDDING_OUTPUT_DIMENSION") else None,
|
|
201
|
+
dtype=os.environ.get("LOKI_EMBEDDING_DTYPE", "float32"),
|
|
187
202
|
chunking_strategy=os.environ.get("LOKI_EMBEDDING_CHUNKING", "semantic"),
|
|
188
203
|
include_context=os.environ.get("LOKI_EMBEDDING_CONTEXT", "true").lower() == "true",
|
|
189
204
|
)
|
|
@@ -203,6 +218,8 @@ class EmbeddingConfig:
|
|
|
203
218
|
model=data.get("model"),
|
|
204
219
|
fallback_providers=data.get("fallback_providers", ["local"]),
|
|
205
220
|
dimension=data.get("dimension", 384),
|
|
221
|
+
output_dimension=data.get("output_dimension"),
|
|
222
|
+
dtype=data.get("dtype", "float32"),
|
|
206
223
|
chunking_strategy=data.get("chunking_strategy", "semantic"),
|
|
207
224
|
max_chunk_size=data.get("max_chunk_size", 512),
|
|
208
225
|
chunk_overlap=data.get("chunk_overlap", 50),
|
|
@@ -222,6 +239,8 @@ class EmbeddingConfig:
|
|
|
222
239
|
"model": self.model,
|
|
223
240
|
"fallback_providers": self.fallback_providers,
|
|
224
241
|
"dimension": self.dimension,
|
|
242
|
+
"output_dimension": self.output_dimension,
|
|
243
|
+
"dtype": self.dtype,
|
|
225
244
|
"chunking_strategy": self.chunking_strategy,
|
|
226
245
|
"max_chunk_size": self.max_chunk_size,
|
|
227
246
|
"chunk_overlap": self.chunk_overlap,
|
|
@@ -469,6 +488,10 @@ def _check_input_type(input_type: str) -> str:
|
|
|
469
488
|
class BaseEmbeddingProvider(ABC):
|
|
470
489
|
"""Base class for embedding providers."""
|
|
471
490
|
|
|
491
|
+
# True when the provider returns unit-length vectors, so a VectorIndex can
|
|
492
|
+
# rank by dot product instead of cosine. Subclasses opt in explicitly.
|
|
493
|
+
normalized: bool = False
|
|
494
|
+
|
|
472
495
|
@abstractmethod
|
|
473
496
|
def embed(self, text: str, input_type: str = "document") -> np.ndarray:
|
|
474
497
|
"""Generate embedding for a single text.
|
|
@@ -507,6 +530,8 @@ class LocalEmbeddingProvider(BaseEmbeddingProvider):
|
|
|
507
530
|
Falls back to TF-IDF when sentence-transformers is not available.
|
|
508
531
|
"""
|
|
509
532
|
|
|
533
|
+
normalized = True
|
|
534
|
+
|
|
510
535
|
def __init__(self, model_name: str = "all-MiniLM-L6-v2", dimension: int = 384):
|
|
511
536
|
self.model_name = model_name
|
|
512
537
|
self.dimension = dimension
|
|
@@ -647,6 +672,8 @@ class LocalEmbeddingProvider(BaseEmbeddingProvider):
|
|
|
647
672
|
class OpenAIEmbeddingProvider(BaseEmbeddingProvider):
|
|
648
673
|
"""OpenAI embedding provider using text-embedding-3 models."""
|
|
649
674
|
|
|
675
|
+
normalized = True
|
|
676
|
+
|
|
650
677
|
def __init__(
|
|
651
678
|
self,
|
|
652
679
|
api_key: Optional[str] = None,
|
|
@@ -810,6 +837,8 @@ class VoyageEmbeddingProvider(BaseEmbeddingProvider):
|
|
|
810
837
|
never selects it.
|
|
811
838
|
"""
|
|
812
839
|
|
|
840
|
+
normalized = True
|
|
841
|
+
|
|
813
842
|
def __init__(
|
|
814
843
|
self,
|
|
815
844
|
api_key: Optional[str] = None,
|
|
@@ -1004,7 +1033,7 @@ class EmbeddingEngine:
|
|
|
1004
1033
|
if provider.is_available():
|
|
1005
1034
|
self._primary_provider = provider
|
|
1006
1035
|
self._current_provider_name = self.config.provider
|
|
1007
|
-
self.dimension = provider.get_dimension()
|
|
1036
|
+
self.dimension = self._effective_dimension(provider.get_dimension())
|
|
1008
1037
|
logger.info(f"Using {self.config.provider} embedding provider")
|
|
1009
1038
|
else:
|
|
1010
1039
|
logger.warning(f"{self.config.provider} provider not available, using fallback")
|
|
@@ -1022,7 +1051,7 @@ class EmbeddingEngine:
|
|
|
1022
1051
|
self._primary_provider = provider
|
|
1023
1052
|
self._current_provider_name = fallback
|
|
1024
1053
|
self._using_fallback = True
|
|
1025
|
-
self.dimension = provider.get_dimension()
|
|
1054
|
+
self.dimension = self._effective_dimension(provider.get_dimension())
|
|
1026
1055
|
self._metrics["fallback_count"] += 1
|
|
1027
1056
|
logger.info(f"Switched to fallback provider: {fallback}")
|
|
1028
1057
|
return
|
|
@@ -1031,7 +1060,7 @@ class EmbeddingEngine:
|
|
|
1031
1060
|
self._primary_provider = self._providers["local"]
|
|
1032
1061
|
self._current_provider_name = "local"
|
|
1033
1062
|
self._using_fallback = True
|
|
1034
|
-
self.dimension = self._primary_provider.get_dimension()
|
|
1063
|
+
self.dimension = self._effective_dimension(self._primary_provider.get_dimension())
|
|
1035
1064
|
|
|
1036
1065
|
def _get_cache_key(
|
|
1037
1066
|
self, text: str, provider: Optional[str] = None, input_type: str = "document"
|
|
@@ -1043,6 +1072,31 @@ class EmbeddingEngine:
|
|
|
1043
1072
|
content = f"{provider_name}:{self.model_name}:{text}{suffix}"
|
|
1044
1073
|
return hashlib.md5(content.encode('utf-8')).hexdigest()
|
|
1045
1074
|
|
|
1075
|
+
def _effective_dimension(self, native: int) -> int:
|
|
1076
|
+
"""Provider dimension after optional output_dimension truncation."""
|
|
1077
|
+
target = self.config.output_dimension
|
|
1078
|
+
return native if target is None else min(native, target)
|
|
1079
|
+
|
|
1080
|
+
def _prepare(self, embedding: np.ndarray) -> np.ndarray:
|
|
1081
|
+
"""Truncate to output_dimension (if set), then L2 normalize."""
|
|
1082
|
+
target = self.config.output_dimension
|
|
1083
|
+
if target is not None and embedding.shape[-1] > target:
|
|
1084
|
+
embedding = embedding[..., :target]
|
|
1085
|
+
return self._normalize(embedding)
|
|
1086
|
+
|
|
1087
|
+
def vector_index_kwargs(self) -> Dict[str, Any]:
|
|
1088
|
+
"""Constructor kwargs for a VectorIndex matching this engine's output.
|
|
1089
|
+
|
|
1090
|
+
``normalized`` follows the active provider's declaration; a provider
|
|
1091
|
+
that does not declare it gets a cosine-ranking index. VectorIndex
|
|
1092
|
+
re-normalizes anything off unit length when the flag is set.
|
|
1093
|
+
"""
|
|
1094
|
+
return {
|
|
1095
|
+
"dimension": self.dimension,
|
|
1096
|
+
"normalized": bool(getattr(self._primary_provider, "normalized", False)),
|
|
1097
|
+
"dtype": self.config.dtype,
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1046
1100
|
def _normalize(self, embedding: np.ndarray) -> np.ndarray:
|
|
1047
1101
|
"""L2 normalize an embedding vector."""
|
|
1048
1102
|
if embedding.ndim == 1:
|
|
@@ -1130,7 +1184,7 @@ class EmbeddingEngine:
|
|
|
1130
1184
|
embedding = np.average(chunk_embeddings, axis=0, weights=weights)
|
|
1131
1185
|
|
|
1132
1186
|
# Normalize
|
|
1133
|
-
embedding = self.
|
|
1187
|
+
embedding = self._prepare(embedding)
|
|
1134
1188
|
|
|
1135
1189
|
# Track metrics
|
|
1136
1190
|
provider_name = self._current_provider_name
|
|
@@ -1153,7 +1207,7 @@ class EmbeddingEngine:
|
|
|
1153
1207
|
weights = np.array([len(c) for c in chunks], dtype=np.float32)
|
|
1154
1208
|
weights = weights / weights.sum()
|
|
1155
1209
|
embedding = np.average(chunk_embeddings, axis=0, weights=weights)
|
|
1156
|
-
embedding = self.
|
|
1210
|
+
embedding = self._prepare(embedding)
|
|
1157
1211
|
# The cache key computed above used the pre-fallback provider name.
|
|
1158
1212
|
# _use_fallback() switched the provider, so recompute the key to
|
|
1159
1213
|
# reflect the provider that actually produced this vector. Without
|
|
@@ -1248,7 +1302,7 @@ class EmbeddingEngine:
|
|
|
1248
1302
|
if texts_to_compute:
|
|
1249
1303
|
try:
|
|
1250
1304
|
new_embeddings = self._primary_provider.embed_batch(texts_to_compute)
|
|
1251
|
-
new_embeddings = self.
|
|
1305
|
+
new_embeddings = self._prepare(new_embeddings)
|
|
1252
1306
|
|
|
1253
1307
|
# Track metrics
|
|
1254
1308
|
provider_name = self._current_provider_name
|
|
@@ -1260,7 +1314,7 @@ class EmbeddingEngine:
|
|
|
1260
1314
|
logger.warning(f"Primary provider failed: {e}, trying fallback")
|
|
1261
1315
|
self._use_fallback()
|
|
1262
1316
|
new_embeddings = self._primary_provider.embed_batch(texts_to_compute)
|
|
1263
|
-
new_embeddings = self.
|
|
1317
|
+
new_embeddings = self._prepare(new_embeddings)
|
|
1264
1318
|
|
|
1265
1319
|
# Update cache
|
|
1266
1320
|
if self.config.cache_enabled:
|
package/memory/vector_index.py
CHANGED
|
@@ -10,6 +10,7 @@ memory system's embedding-based search capabilities.
|
|
|
10
10
|
from __future__ import annotations
|
|
11
11
|
|
|
12
12
|
import json
|
|
13
|
+
import math
|
|
13
14
|
import os
|
|
14
15
|
from typing import Callable, Dict, List, Optional, Tuple
|
|
15
16
|
|
|
@@ -35,13 +36,26 @@ class VectorIndex:
|
|
|
35
36
|
metadata: List of metadata dictionaries for each vector.
|
|
36
37
|
"""
|
|
37
38
|
|
|
38
|
-
|
|
39
|
+
SUPPORTED_DTYPES = ("float32", "float16")
|
|
40
|
+
|
|
41
|
+
def __init__(
|
|
42
|
+
self,
|
|
43
|
+
dimension: int = 384,
|
|
44
|
+
normalized: bool = False,
|
|
45
|
+
dtype: str = "float32",
|
|
46
|
+
):
|
|
39
47
|
"""
|
|
40
48
|
Initialize a new vector index.
|
|
41
49
|
|
|
42
50
|
Args:
|
|
43
51
|
dimension: The dimensionality of vectors. Default is 384
|
|
44
52
|
which matches MiniLM embedding size.
|
|
53
|
+
normalized: True when every vector added is already unit length
|
|
54
|
+
(a provider that declares ``normalized``). Search then
|
|
55
|
+
ranks by plain dot product, which equals cosine for unit
|
|
56
|
+
vectors, and skips the per-search normalized copy.
|
|
57
|
+
dtype: Storage dtype for vectors, "float32" (default) or
|
|
58
|
+
"float16". Scoring always runs in float32.
|
|
45
59
|
|
|
46
60
|
Raises:
|
|
47
61
|
ImportError: If numpy is not installed. Every operation in this
|
|
@@ -56,13 +70,32 @@ class VectorIndex:
|
|
|
56
70
|
"numpy is required for the vector index. "
|
|
57
71
|
"Install it with: pip install numpy"
|
|
58
72
|
)
|
|
73
|
+
if dtype not in self.SUPPORTED_DTYPES:
|
|
74
|
+
raise ValueError(
|
|
75
|
+
f"dtype must be one of {self.SUPPORTED_DTYPES}, got {dtype!r}"
|
|
76
|
+
)
|
|
59
77
|
self.dimension = dimension
|
|
78
|
+
self.assume_normalized = normalized
|
|
79
|
+
self.dtype = dtype
|
|
60
80
|
self.embeddings: List[np.ndarray] = []
|
|
61
81
|
self.ids: List[str] = []
|
|
62
82
|
self.metadata: List[Dict] = []
|
|
63
83
|
self._normalized: bool = False
|
|
64
84
|
self._id_to_index: Dict[str, int] = {}
|
|
65
85
|
|
|
86
|
+
def _store(self, embedding: np.ndarray) -> np.ndarray:
|
|
87
|
+
"""Cast a vector to the storage dtype. A normalized index holds unit
|
|
88
|
+
vectors only: anything off unit length is re-normalized in float32
|
|
89
|
+
first, so a caller's non-unit vector can never inflate dot-product
|
|
90
|
+
scores. A zero or non-finite vector is stored as is, never divided."""
|
|
91
|
+
vec = np.asarray(embedding)
|
|
92
|
+
if self.assume_normalized:
|
|
93
|
+
vec = vec.astype(np.float32)
|
|
94
|
+
norm = float(np.linalg.norm(vec.astype(np.float64)))
|
|
95
|
+
if math.isfinite(norm) and norm > 0 and abs(norm - 1.0) > 1e-6:
|
|
96
|
+
vec = vec / norm
|
|
97
|
+
return vec.astype(self.dtype)
|
|
98
|
+
|
|
66
99
|
def add(
|
|
67
100
|
self,
|
|
68
101
|
id: str,
|
|
@@ -95,7 +128,7 @@ class VectorIndex:
|
|
|
95
128
|
return
|
|
96
129
|
|
|
97
130
|
# Add new entry
|
|
98
|
-
self.embeddings.append(
|
|
131
|
+
self.embeddings.append(self._store(embedding))
|
|
99
132
|
self.ids.append(id)
|
|
100
133
|
self.metadata.append(metadata or {})
|
|
101
134
|
self._id_to_index[id] = len(self.ids) - 1
|
|
@@ -154,7 +187,8 @@ class VectorIndex:
|
|
|
154
187
|
"""
|
|
155
188
|
Find the top-k most similar vectors to the query.
|
|
156
189
|
|
|
157
|
-
Uses cosine similarity for ranking
|
|
190
|
+
Uses cosine similarity for ranking (a plain dot product when the
|
|
191
|
+
index was created with normalized=True).
|
|
158
192
|
|
|
159
193
|
Args:
|
|
160
194
|
query: The query vector to search for.
|
|
@@ -179,15 +213,17 @@ class VectorIndex:
|
|
|
179
213
|
f"index dimension {self.dimension}"
|
|
180
214
|
)
|
|
181
215
|
|
|
182
|
-
# Ensure vectors are normalized for cosine similarity
|
|
183
|
-
if not self._normalized:
|
|
184
|
-
self._normalize_vectors()
|
|
185
|
-
|
|
186
216
|
# Normalize query
|
|
187
217
|
query_norm = query / (np.linalg.norm(query) + 1e-10)
|
|
188
218
|
|
|
189
|
-
|
|
190
|
-
|
|
219
|
+
if self.assume_normalized:
|
|
220
|
+
# Unit-length vectors: dot product equals cosine, no copy needed.
|
|
221
|
+
embeddings_matrix = np.vstack(self.embeddings).astype(np.float32)
|
|
222
|
+
else:
|
|
223
|
+
# Ensure vectors are normalized for cosine similarity
|
|
224
|
+
if not self._normalized:
|
|
225
|
+
self._normalize_vectors()
|
|
226
|
+
embeddings_matrix = np.vstack(self._normalized_embeddings).astype(np.float32)
|
|
191
227
|
|
|
192
228
|
# Compute cosine similarities
|
|
193
229
|
similarities = np.dot(embeddings_matrix, query_norm)
|
|
@@ -264,7 +300,7 @@ class VectorIndex:
|
|
|
264
300
|
f"Embedding dimension {embedding.shape[0]} does not match "
|
|
265
301
|
f"index dimension {self.dimension}"
|
|
266
302
|
)
|
|
267
|
-
self.embeddings[index] =
|
|
303
|
+
self.embeddings[index] = self._store(embedding)
|
|
268
304
|
self._normalized = False
|
|
269
305
|
|
|
270
306
|
if metadata is not None:
|
|
@@ -321,6 +357,9 @@ class VectorIndex:
|
|
|
321
357
|
"metadata": self.metadata,
|
|
322
358
|
"dimension": self.dimension
|
|
323
359
|
}
|
|
360
|
+
if self.assume_normalized:
|
|
361
|
+
# Written only when set, so a default index keeps its byte layout.
|
|
362
|
+
sidecar_data["normalized"] = True
|
|
324
363
|
|
|
325
364
|
import tempfile
|
|
326
365
|
json_path = f"{path}.json"
|
|
@@ -371,9 +410,16 @@ class VectorIndex:
|
|
|
371
410
|
self.ids = sidecar_data["ids"]
|
|
372
411
|
self.metadata = sidecar_data["metadata"]
|
|
373
412
|
|
|
374
|
-
#
|
|
413
|
+
# A file saved by a normalized index, or an index that claims
|
|
414
|
+
# normalized, ranks by dot product: validate by re-normalizing.
|
|
415
|
+
if sidecar_data.get("normalized") is True:
|
|
416
|
+
self.assume_normalized = True
|
|
417
|
+
|
|
418
|
+
# Convert embeddings matrix to list, cast to this index's dtype
|
|
419
|
+
# (and unit length when normalized) so a float16 file does not leave
|
|
420
|
+
# a float32 index half precision and an old non-unit file scores right.
|
|
375
421
|
if embeddings_matrix.shape[0] > 0:
|
|
376
|
-
self.embeddings = [embeddings_matrix[i] for i in range(embeddings_matrix.shape[0])]
|
|
422
|
+
self.embeddings = [self._store(embeddings_matrix[i]) for i in range(embeddings_matrix.shape[0])]
|
|
377
423
|
else:
|
|
378
424
|
self.embeddings = []
|
|
379
425
|
|
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": "11.
|
|
4
|
+
"version": "11.46.0",
|
|
5
5
|
"description": "An autonomous software factory that knows what it is supposed to deliver, and proves it did.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"agent",
|
|
@@ -160,5 +160,5 @@
|
|
|
160
160
|
"dependencies": {
|
|
161
161
|
"@resvg/resvg-wasm": "^2.6.2"
|
|
162
162
|
},
|
|
163
|
-
"gitHead": "
|
|
163
|
+
"gitHead": "426ac88090247c972081b0c6bf078068c21f8e4e"
|
|
164
164
|
}
|
|
@@ -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": "11.
|
|
5
|
+
"version": "11.46.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",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{c as L,r as x,j as e,w as re,Z as ne,m as le,h as ie,p as P,F as ye,U as I,X as ce,L as de,x as oe,M as Ae,T as Z,S as we,l as xe,k as me,y as Ce,E as Fe,a0 as Se,a as U,a2 as he}from"./index-
|
|
1
|
+
import{c as L,r as x,j as e,w as re,Z as ne,m as le,h as ie,p as P,F as ye,U as I,X as ce,L as de,x as oe,M as Ae,T as Z,S as we,l as xe,k as me,y as Ce,E as Fe,a0 as Se,a as U,a2 as he}from"./index-CjeJkKHf.js";import{B as C}from"./Button-BDJQTeBq.js";import{T as $e}from"./trending-up-Bqln1HBv.js";import{C as z}from"./clock-W2kDTGYx.js";import{A as Be,U as ue,M as De}from"./Avatar-xfdA6HHw.js";import{A as J}from"./activity-onNTo3z1.js";import{R as pe}from"./refresh-cw-B-eHLtrF.js";import{G as ze}from"./globe-mb1Su4WH.js";import{C as Le}from"./chevron-left-D8M7-5Kc.js";import{C as je}from"./check-_TVDwdrq.js";import{D as Y}from"./dollar-sign-Be49Rzh5.js";import{U as Te}from"./user-BhFi92qW.js";import{D as Me}from"./database-Dg9kxuUW.js";import{L as Ue}from"./lock-DyfnnkPv.js";import{S as Re}from"./scroll-text-BfFjI8cR.js";import{S as Ie}from"./shield-alert-Bojfzk9R.js";/**
|
|
2
2
|
* @license lucide-react v0.577.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as e}from"./index-
|
|
1
|
+
import{j as e}from"./index-CjeJkKHf.js";import{C as r}from"./clock-W2kDTGYx.js";import{C as a}from"./circle-alert-HUO4WzPf.js";import{C as l}from"./check-_TVDwdrq.js";const i={completed:"bg-[#1FC5A8]/10 text-[#1FC5A8]",running:"bg-[#553DE9]/10 text-[#553DE9]",failed:"bg-[#C45B5B]/10 text-[#C45B5B]",started:"bg-[#D4A03C]/10 text-[#D4A03C]",empty:"bg-[#F8F4F0] text-[#6B6960]",version:"bg-[#553DE9]/10 text-[#553DE9]"};function o({status:t}){switch(t){case"completed":return e.jsx(l,{size:12});case"running":return e.jsxs("span",{className:"relative flex h-2 w-2",children:[e.jsx("span",{className:"animate-ping motion-reduce:animate-none absolute inline-flex h-full w-full rounded-full bg-current opacity-75"}),e.jsx("span",{className:"relative inline-flex rounded-full h-2 w-2 bg-current"})]});case"failed":return e.jsx(a,{size:12});case"started":return e.jsx(r,{size:12});default:return null}}function f({status:t,children:n,className:s=""}){return e.jsxs("span",{className:["inline-flex items-center gap-1 rounded-btn px-2.5 py-0.5 text-xs font-semibold",i[t],s].filter(Boolean).join(" "),children:[e.jsx(o,{status:t}),n]})}export{f as B};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as p,j as t}from"./index-
|
|
1
|
+
import{r as p,j as t}from"./index-CjeJkKHf.js";const m={primary:"bg-[#553DE9] text-white hover:bg-[#4432c4] shadow-button rounded-btn",secondary:"border border-[#553DE9] text-[#553DE9] hover:bg-[#E8E4FD] bg-transparent rounded-btn",ghost:"text-[#36342E] hover:bg-[#F8F4F0] rounded-btn",danger:"bg-[#C45B5B]/10 text-[#C45B5B] border border-[#C45B5B]/20 hover:bg-[#C45B5B]/20 rounded-btn"},b={sm:"px-3 py-1.5 text-xs",md:"px-4 py-2 text-sm",lg:"px-6 py-3 text-base"},u={sm:14,md:16,lg:18};function h({size:e}){return t.jsxs("svg",{className:"animate-spin",width:e,height:e,viewBox:"0 0 24 24",fill:"none",children:[t.jsx("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),t.jsx("path",{className:"opacity-75",fill:"currentColor",d:"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"})]})}const B=p.forwardRef(({variant:e="primary",size:o="md",icon:n,iconRight:i,loading:r=!1,disabled:a,className:c="",children:l,...x},d)=>{const s=u[o];return t.jsxs("button",{ref:d,disabled:a||r,className:["inline-flex items-center justify-center gap-2 font-medium transition-colors",m[e],b[o],(a||r)&&"opacity-60 cursor-not-allowed",c].filter(Boolean).join(" "),...x,children:[r?t.jsx(h,{size:s}):n?t.jsx(n,{size:s}):null,l,i&&!r&&t.jsx(i,{size:s})]})});B.displayName="Button";export{B};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{c as $,r as l,j as e,G as we,Q as Se,F as Ce,h as Re,T as U,Z as Ee,a as S,V as Me,S as $e,Y as Te,X as Pe,P as ie,i as Ae,g as ze,C as Ie,l as Le,N as I,J as _e,K as De,O as Fe,u as Oe}from"./index-
|
|
1
|
+
import{c as $,r as l,j as e,G as we,Q as Se,F as Ce,h as Re,T as U,Z as Ee,a as S,V as Me,S as $e,Y as Te,X as Pe,P as ie,i as Ae,g as ze,C as Ie,l as Le,N as I,J as _e,K as De,O as Fe,u as Oe}from"./index-CjeJkKHf.js";import{P as K,S as He,E as Be}from"./ErrorBoundary-BGAlBzcB.js";import{C as qe,F as Ge,M as Ue,H as Ke,a as We,G as Ve,T as Qe}from"./thumbs-up-BsB7OQxT.js";import{C as oe}from"./check-_TVDwdrq.js";import{C as Ye}from"./clock-W2kDTGYx.js";import{D as Xe}from"./dollar-sign-Be49Rzh5.js";import{U as Ze}from"./upload-CNpkqzkA.js";import{L as V}from"./loader-circle-DZFGHRZb.js";/**
|
|
2
2
|
* @license lucide-react v0.577.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as o,j as e}from"./index-C2ryWVlq.js";function f({value:r,prefix:t="",suffix:s=""}){const[u,n]=o.useState(0),c=o.useRef(0);return o.useEffect(()=>{const a=c.current,h=r-a;if(h===0)return;const i=600,d=performance.now();function l(b){const v=b-d,m=Math.min(v/i,1),N=1-Math.pow(1-m,3),p=Math.round(a+h*N);n(p),c.current=p,m<1&&requestAnimationFrame(l)}requestAnimationFrame(l)},[r]),e.jsxs("span",{className:"tabular-nums",children:[t,u.toLocaleString(),s]})}function g(){const[r,t]=o.useState(5),[s,u]=o.useState(30),[n,c]=o.useState(75),a=.4,i=Math.round(r*s*a*4.33),d=Math.round(i*n);return e.jsxs("div",{className:"bg-white border border-[#ECEAE3] rounded-xl p-6 shadow-sm",children:[e.jsx("h3",{className:"text-lg font-bold text-[#36342E] mb-1",children:"ROI Calculator"}),e.jsx("p",{className:"text-sm text-[#6B6960] mb-6",children:"Estimate how much your team could save with autonomous development."}),e.jsxs("div",{className:"space-y-5",children:[e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-2",children:[e.jsx("label",{className:"text-sm font-medium text-[#36342E]",children:"Team size"}),e.jsxs("span",{className:"text-sm font-semibold text-[#553DE9] tabular-nums",children:[r," developers"]})]}),e.jsx("input",{type:"range",min:1,max:50,value:r,onChange:l=>t(Number(l.target.value)),className:"w-full h-2 bg-[#ECEAE3] rounded-full appearance-none cursor-pointer accent-[#553DE9]"}),e.jsxs("div",{className:"flex justify-between text-xs text-[#939084] mt-1",children:[e.jsx("span",{children:"1"}),e.jsx("span",{children:"50"})]})]}),e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-2",children:[e.jsx("label",{className:"text-sm font-medium text-[#36342E]",children:"Hours coding per week"}),e.jsxs("span",{className:"text-sm font-semibold text-[#553DE9] tabular-nums",children:[s,"h"]})]}),e.jsx("input",{type:"range",min:5,max:60,value:s,onChange:l=>u(Number(l.target.value)),className:"w-full h-2 bg-[#ECEAE3] rounded-full appearance-none cursor-pointer accent-[#553DE9]"}),e.jsxs("div",{className:"flex justify-between text-xs text-[#939084] mt-1",children:[e.jsx("span",{children:"5h"}),e.jsx("span",{children:"60h"})]})]}),e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-2",children:[e.jsx("label",{className:"text-sm font-medium text-[#36342E]",children:"Average hourly rate"}),e.jsxs("span",{className:"text-sm font-semibold text-[#553DE9] tabular-nums",children:["$",n,"/hr"]})]}),e.jsx("input",{type:"range",min:25,max:250,step:5,value:n,onChange:l=>c(Number(l.target.value)),className:"w-full h-2 bg-[#ECEAE3] rounded-full appearance-none cursor-pointer accent-[#553DE9]"}),e.jsxs("div",{className:"flex justify-between text-xs text-[#939084] mt-1",children:[e.jsx("span",{children:"$25"}),e.jsx("span",{children:"$250"})]})]})]}),e.jsxs("div",{className:"mt-6 pt-6 border-t border-[#ECEAE3]",children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4 text-center",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-2xl font-bold text-[#553DE9]",children:e.jsx(f,{value:i,suffix:"h"})}),e.jsx("div",{className:"text-xs text-[#6B6960] mt-1",children:"Est. hours saved / month"})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-2xl font-bold text-[#1FC5A8]",children:e.jsx(f,{value:d,prefix:"$"})}),e.jsx("div",{className:"text-xs text-[#6B6960] mt-1",children:"Est. cost saved / month"})]})]}),e.jsxs("div",{className:"mt-4 p-3 rounded-lg bg-[#553DE9]/5 border border-[#553DE9]/10",children:[e.jsxs("p",{className:"text-sm text-[#36342E] text-center",children:["If Loki Mode saved ",Math.round(a*100),"% of coding time, your team could save"," ",e.jsxs("span",{className:"font-bold text-[#553DE9]",children:[i.toLocaleString()," hours"]})," ","and"," ",e.jsxs("span",{className:"font-bold text-[#1FC5A8]",children:["$",d.toLocaleString()]})," ","per month."]}),e.jsxs("p",{className:"mt-2 text-xs text-[#6B6960] text-center",children:["The ",Math.round(a*100),"% is an assumption, not a measurement. Model and API spend is not included."]})]})]})]})}const j=[{feature:"Claude (Opus/Sonnet/Haiku)",category:"AI Models",lokiMode:!0,boltNew:!1,replit:!1,lovable:!0},{feature:"GPT-4o / Codex",category:"AI Models",lokiMode:!0,boltNew:!0,replit:!0,lovable:!1},{feature:"5-provider auto-failover",category:"AI Models",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1},{feature:"8 automated quality gates",category:"Quality",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1},{feature:"Blind 3-reviewer code review",category:"Quality",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1},{feature:"Anti-sycophancy checks",category:"Quality",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1},{feature:"Automated test generation",category:"Quality",lokiMode:!0,boltNew:!1,replit:"Partial",lovable:!1},{feature:"Docker container generation",category:"Deployment",lokiMode:!0,boltNew:!1,replit:!0,lovable:!1},{feature:"CI/CD pipeline generation",category:"Deployment",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1},{feature:"One-click cloud deploy",category:"Deployment",lokiMode:"Planned",boltNew:!0,replit:!0,lovable:!0},{feature:"Self-hosted (your keys)",category:"Cost",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1},{feature:"Free tier available",category:"Cost",lokiMode:"Source-available (BUSL-1.1)",boltNew:!0,replit:!0,lovable:!0},{feature:"No vendor lock-in",category:"Cost",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1},{feature:"SSO / OIDC authentication",category:"Enterprise",lokiMode:!0,boltNew:!1,replit:!0,lovable:!1},{feature:"RBAC access control",category:"Enterprise",lokiMode:!0,boltNew:!1,replit:!0,lovable:!1},{feature:"Audit logging",category:"Enterprise",lokiMode:!0,boltNew:!1,replit:!0,lovable:!1},{feature:"Air-gapped deployment",category:"Enterprise",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1}];function y(){return e.jsx("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",className:"text-[#1FC5A8]",children:e.jsx("path",{d:"M20 6L9 17l-5-5",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round",strokeLinejoin:"round"})})}function w(){return e.jsx("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",className:"text-[#C45B5B]/40",children:e.jsx("path",{d:"M18 6L6 18M6 6l12 12",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})})}function x({value:r}){return typeof r=="string"?e.jsx("span",{className:"text-xs text-[#6B6960] font-medium",children:r}):r?e.jsx(y,{}):e.jsx(w,{})}const k=[{title:"Full Autonomy",description:"Describe what you want. Loki Mode handles planning, coding, testing, and verification automatically.",icon:e.jsx("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",className:"text-[#553DE9]",children:e.jsx("path",{d:"M13 2L3 14h9l-1 8 10-12h-9l1-8z",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})})},{title:"Production Quality",description:"8 quality gates, blind code review, and anti-sycophancy checks ensure code that actually works.",icon:e.jsx("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",className:"text-[#1FC5A8]",children:e.jsx("path",{d:"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})})},{title:"Your Infrastructure",description:"Self-hosted, source-available (BUSL-1.1), no data leaves your network. Use your own API keys across 5 providers.",icon:e.jsxs("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",className:"text-[#2F71E3]",children:[e.jsx("rect",{x:"2",y:"2",width:"20",height:"8",rx:"2",stroke:"currentColor",strokeWidth:"2"}),e.jsx("rect",{x:"2",y:"14",width:"20",height:"8",rx:"2",stroke:"currentColor",strokeWidth:"2"}),e.jsx("circle",{cx:"6",cy:"6",r:"1",fill:"currentColor"}),e.jsx("circle",{cx:"6",cy:"18",r:"1",fill:"currentColor"})]})},{title:"Built for Teams",description:"Enterprise auth, RBAC, audit logs, and parallel workflows for teams of any size.",icon:e.jsxs("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",className:"text-[#E93D82]",children:[e.jsx("path",{d:"M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"}),e.jsx("circle",{cx:"9",cy:"7",r:"4",stroke:"currentColor",strokeWidth:"2"}),e.jsx("path",{d:"M23 21v-2a4 4 0 00-3-3.87M16 3.13a4 4 0 010 7.75",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})]})}];function C(){const r=[...new Set(j.map(t=>t.category))];return e.jsx("div",{className:"min-h-screen bg-[#FAF9F6]",children:e.jsxs("div",{className:"max-w-6xl mx-auto px-6 py-8",children:[e.jsxs("div",{className:"mb-8",children:[e.jsx("h1",{className:"text-2xl font-bold text-[#36342E]",children:"Compare"}),e.jsx("p",{className:"text-[#6B6960] mt-1",children:"See how Loki Mode stacks up against other AI development platforms."})]}),e.jsx("div",{className:"bg-white border border-[#ECEAE3] rounded-xl overflow-hidden shadow-sm",children:e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b border-[#ECEAE3]",children:[e.jsx("th",{className:"text-left px-4 py-3 font-medium text-[#6B6960] w-[240px]",children:"Feature"}),e.jsx("th",{className:"text-center px-4 py-3 font-bold text-[#553DE9] bg-[#553DE9]/5 w-[130px]",children:"Loki Mode"}),e.jsx("th",{className:"text-center px-4 py-3 font-medium text-[#6B6960] w-[130px]",children:"bolt.new"}),e.jsx("th",{className:"text-center px-4 py-3 font-medium text-[#6B6960] w-[130px]",children:"Replit"}),e.jsx("th",{className:"text-center px-4 py-3 font-medium text-[#6B6960] w-[130px]",children:"Lovable"})]})}),e.jsx("tbody",{children:r.map(t=>e.jsxs(e.Fragment,{children:[e.jsx("tr",{className:"bg-[#FAF9F6]",children:e.jsx("td",{colSpan:5,className:"px-4 py-2 text-xs font-bold text-[#939084] uppercase tracking-wider",children:t})},`cat-${t}`),j.filter(s=>s.category===t).map(s=>e.jsxs("tr",{className:"border-b border-[#ECEAE3] last:border-b-0",children:[e.jsx("td",{className:"px-4 py-2.5 text-[#36342E]",children:s.feature}),e.jsx("td",{className:"px-4 py-2.5 text-center bg-[#553DE9]/5",children:e.jsx("div",{className:"flex justify-center",children:e.jsx(x,{value:s.lokiMode})})}),e.jsx("td",{className:"px-4 py-2.5 text-center",children:e.jsx("div",{className:"flex justify-center",children:e.jsx(x,{value:s.boltNew})})}),e.jsx("td",{className:"px-4 py-2.5 text-center",children:e.jsx("div",{className:"flex justify-center",children:e.jsx(x,{value:s.replit})})}),e.jsx("td",{className:"px-4 py-2.5 text-center",children:e.jsx("div",{className:"flex justify-center",children:e.jsx(x,{value:s.lovable})})})]},s.feature))]}))})]})})}),e.jsxs("div",{className:"mt-12",children:[e.jsx("h2",{className:"text-xl font-bold text-[#36342E] mb-6",children:"Why developers choose Loki Mode"}),e.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-5",children:k.map(t=>e.jsxs("div",{className:"bg-white border border-[#ECEAE3] rounded-xl p-5 shadow-sm hover:shadow-md transition-shadow",children:[e.jsx("div",{className:"mb-3",children:t.icon}),e.jsx("h3",{className:"text-base font-bold text-[#36342E] mb-1",children:t.title}),e.jsx("p",{className:"text-sm text-[#6B6960]",children:t.description})]},t.title))})]}),e.jsx("div",{className:"mt-12 max-w-xl mx-auto",children:e.jsx(g,{})})]})})}export{C as default};
|
|
1
|
+
import{r as o,j as e}from"./index-CjeJkKHf.js";function f({value:r,prefix:t="",suffix:s=""}){const[u,n]=o.useState(0),c=o.useRef(0);return o.useEffect(()=>{const a=c.current,h=r-a;if(h===0)return;const i=600,d=performance.now();function l(b){const v=b-d,m=Math.min(v/i,1),N=1-Math.pow(1-m,3),p=Math.round(a+h*N);n(p),c.current=p,m<1&&requestAnimationFrame(l)}requestAnimationFrame(l)},[r]),e.jsxs("span",{className:"tabular-nums",children:[t,u.toLocaleString(),s]})}function g(){const[r,t]=o.useState(5),[s,u]=o.useState(30),[n,c]=o.useState(75),a=.4,i=Math.round(r*s*a*4.33),d=Math.round(i*n);return e.jsxs("div",{className:"bg-white border border-[#ECEAE3] rounded-xl p-6 shadow-sm",children:[e.jsx("h3",{className:"text-lg font-bold text-[#36342E] mb-1",children:"ROI Calculator"}),e.jsx("p",{className:"text-sm text-[#6B6960] mb-6",children:"Estimate how much your team could save with autonomous development."}),e.jsxs("div",{className:"space-y-5",children:[e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-2",children:[e.jsx("label",{className:"text-sm font-medium text-[#36342E]",children:"Team size"}),e.jsxs("span",{className:"text-sm font-semibold text-[#553DE9] tabular-nums",children:[r," developers"]})]}),e.jsx("input",{type:"range",min:1,max:50,value:r,onChange:l=>t(Number(l.target.value)),className:"w-full h-2 bg-[#ECEAE3] rounded-full appearance-none cursor-pointer accent-[#553DE9]"}),e.jsxs("div",{className:"flex justify-between text-xs text-[#939084] mt-1",children:[e.jsx("span",{children:"1"}),e.jsx("span",{children:"50"})]})]}),e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-2",children:[e.jsx("label",{className:"text-sm font-medium text-[#36342E]",children:"Hours coding per week"}),e.jsxs("span",{className:"text-sm font-semibold text-[#553DE9] tabular-nums",children:[s,"h"]})]}),e.jsx("input",{type:"range",min:5,max:60,value:s,onChange:l=>u(Number(l.target.value)),className:"w-full h-2 bg-[#ECEAE3] rounded-full appearance-none cursor-pointer accent-[#553DE9]"}),e.jsxs("div",{className:"flex justify-between text-xs text-[#939084] mt-1",children:[e.jsx("span",{children:"5h"}),e.jsx("span",{children:"60h"})]})]}),e.jsxs("div",{children:[e.jsxs("div",{className:"flex items-center justify-between mb-2",children:[e.jsx("label",{className:"text-sm font-medium text-[#36342E]",children:"Average hourly rate"}),e.jsxs("span",{className:"text-sm font-semibold text-[#553DE9] tabular-nums",children:["$",n,"/hr"]})]}),e.jsx("input",{type:"range",min:25,max:250,step:5,value:n,onChange:l=>c(Number(l.target.value)),className:"w-full h-2 bg-[#ECEAE3] rounded-full appearance-none cursor-pointer accent-[#553DE9]"}),e.jsxs("div",{className:"flex justify-between text-xs text-[#939084] mt-1",children:[e.jsx("span",{children:"$25"}),e.jsx("span",{children:"$250"})]})]})]}),e.jsxs("div",{className:"mt-6 pt-6 border-t border-[#ECEAE3]",children:[e.jsxs("div",{className:"grid grid-cols-2 gap-4 text-center",children:[e.jsxs("div",{children:[e.jsx("div",{className:"text-2xl font-bold text-[#553DE9]",children:e.jsx(f,{value:i,suffix:"h"})}),e.jsx("div",{className:"text-xs text-[#6B6960] mt-1",children:"Est. hours saved / month"})]}),e.jsxs("div",{children:[e.jsx("div",{className:"text-2xl font-bold text-[#1FC5A8]",children:e.jsx(f,{value:d,prefix:"$"})}),e.jsx("div",{className:"text-xs text-[#6B6960] mt-1",children:"Est. cost saved / month"})]})]}),e.jsxs("div",{className:"mt-4 p-3 rounded-lg bg-[#553DE9]/5 border border-[#553DE9]/10",children:[e.jsxs("p",{className:"text-sm text-[#36342E] text-center",children:["If Loki Mode saved ",Math.round(a*100),"% of coding time, your team could save"," ",e.jsxs("span",{className:"font-bold text-[#553DE9]",children:[i.toLocaleString()," hours"]})," ","and"," ",e.jsxs("span",{className:"font-bold text-[#1FC5A8]",children:["$",d.toLocaleString()]})," ","per month."]}),e.jsxs("p",{className:"mt-2 text-xs text-[#6B6960] text-center",children:["The ",Math.round(a*100),"% is an assumption, not a measurement. Model and API spend is not included."]})]})]})]})}const j=[{feature:"Claude (Opus/Sonnet/Haiku)",category:"AI Models",lokiMode:!0,boltNew:!1,replit:!1,lovable:!0},{feature:"GPT-4o / Codex",category:"AI Models",lokiMode:!0,boltNew:!0,replit:!0,lovable:!1},{feature:"5-provider auto-failover",category:"AI Models",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1},{feature:"8 automated quality gates",category:"Quality",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1},{feature:"Blind 3-reviewer code review",category:"Quality",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1},{feature:"Anti-sycophancy checks",category:"Quality",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1},{feature:"Automated test generation",category:"Quality",lokiMode:!0,boltNew:!1,replit:"Partial",lovable:!1},{feature:"Docker container generation",category:"Deployment",lokiMode:!0,boltNew:!1,replit:!0,lovable:!1},{feature:"CI/CD pipeline generation",category:"Deployment",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1},{feature:"One-click cloud deploy",category:"Deployment",lokiMode:"Planned",boltNew:!0,replit:!0,lovable:!0},{feature:"Self-hosted (your keys)",category:"Cost",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1},{feature:"Free tier available",category:"Cost",lokiMode:"Source-available (BUSL-1.1)",boltNew:!0,replit:!0,lovable:!0},{feature:"No vendor lock-in",category:"Cost",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1},{feature:"SSO / OIDC authentication",category:"Enterprise",lokiMode:!0,boltNew:!1,replit:!0,lovable:!1},{feature:"RBAC access control",category:"Enterprise",lokiMode:!0,boltNew:!1,replit:!0,lovable:!1},{feature:"Audit logging",category:"Enterprise",lokiMode:!0,boltNew:!1,replit:!0,lovable:!1},{feature:"Air-gapped deployment",category:"Enterprise",lokiMode:!0,boltNew:!1,replit:!1,lovable:!1}];function y(){return e.jsx("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",className:"text-[#1FC5A8]",children:e.jsx("path",{d:"M20 6L9 17l-5-5",stroke:"currentColor",strokeWidth:"2.5",strokeLinecap:"round",strokeLinejoin:"round"})})}function w(){return e.jsx("svg",{width:"18",height:"18",viewBox:"0 0 24 24",fill:"none",className:"text-[#C45B5B]/40",children:e.jsx("path",{d:"M18 6L6 18M6 6l12 12",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})})}function x({value:r}){return typeof r=="string"?e.jsx("span",{className:"text-xs text-[#6B6960] font-medium",children:r}):r?e.jsx(y,{}):e.jsx(w,{})}const k=[{title:"Full Autonomy",description:"Describe what you want. Loki Mode handles planning, coding, testing, and verification automatically.",icon:e.jsx("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",className:"text-[#553DE9]",children:e.jsx("path",{d:"M13 2L3 14h9l-1 8 10-12h-9l1-8z",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})})},{title:"Production Quality",description:"8 quality gates, blind code review, and anti-sycophancy checks ensure code that actually works.",icon:e.jsx("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",className:"text-[#1FC5A8]",children:e.jsx("path",{d:"M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})})},{title:"Your Infrastructure",description:"Self-hosted, source-available (BUSL-1.1), no data leaves your network. Use your own API keys across 5 providers.",icon:e.jsxs("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",className:"text-[#2F71E3]",children:[e.jsx("rect",{x:"2",y:"2",width:"20",height:"8",rx:"2",stroke:"currentColor",strokeWidth:"2"}),e.jsx("rect",{x:"2",y:"14",width:"20",height:"8",rx:"2",stroke:"currentColor",strokeWidth:"2"}),e.jsx("circle",{cx:"6",cy:"6",r:"1",fill:"currentColor"}),e.jsx("circle",{cx:"6",cy:"18",r:"1",fill:"currentColor"})]})},{title:"Built for Teams",description:"Enterprise auth, RBAC, audit logs, and parallel workflows for teams of any size.",icon:e.jsxs("svg",{width:"24",height:"24",viewBox:"0 0 24 24",fill:"none",className:"text-[#E93D82]",children:[e.jsx("path",{d:"M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"}),e.jsx("circle",{cx:"9",cy:"7",r:"4",stroke:"currentColor",strokeWidth:"2"}),e.jsx("path",{d:"M23 21v-2a4 4 0 00-3-3.87M16 3.13a4 4 0 010 7.75",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})]})}];function C(){const r=[...new Set(j.map(t=>t.category))];return e.jsx("div",{className:"min-h-screen bg-[#FAF9F6]",children:e.jsxs("div",{className:"max-w-6xl mx-auto px-6 py-8",children:[e.jsxs("div",{className:"mb-8",children:[e.jsx("h1",{className:"text-2xl font-bold text-[#36342E]",children:"Compare"}),e.jsx("p",{className:"text-[#6B6960] mt-1",children:"See how Loki Mode stacks up against other AI development platforms."})]}),e.jsx("div",{className:"bg-white border border-[#ECEAE3] rounded-xl overflow-hidden shadow-sm",children:e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b border-[#ECEAE3]",children:[e.jsx("th",{className:"text-left px-4 py-3 font-medium text-[#6B6960] w-[240px]",children:"Feature"}),e.jsx("th",{className:"text-center px-4 py-3 font-bold text-[#553DE9] bg-[#553DE9]/5 w-[130px]",children:"Loki Mode"}),e.jsx("th",{className:"text-center px-4 py-3 font-medium text-[#6B6960] w-[130px]",children:"bolt.new"}),e.jsx("th",{className:"text-center px-4 py-3 font-medium text-[#6B6960] w-[130px]",children:"Replit"}),e.jsx("th",{className:"text-center px-4 py-3 font-medium text-[#6B6960] w-[130px]",children:"Lovable"})]})}),e.jsx("tbody",{children:r.map(t=>e.jsxs(e.Fragment,{children:[e.jsx("tr",{className:"bg-[#FAF9F6]",children:e.jsx("td",{colSpan:5,className:"px-4 py-2 text-xs font-bold text-[#939084] uppercase tracking-wider",children:t})},`cat-${t}`),j.filter(s=>s.category===t).map(s=>e.jsxs("tr",{className:"border-b border-[#ECEAE3] last:border-b-0",children:[e.jsx("td",{className:"px-4 py-2.5 text-[#36342E]",children:s.feature}),e.jsx("td",{className:"px-4 py-2.5 text-center bg-[#553DE9]/5",children:e.jsx("div",{className:"flex justify-center",children:e.jsx(x,{value:s.lokiMode})})}),e.jsx("td",{className:"px-4 py-2.5 text-center",children:e.jsx("div",{className:"flex justify-center",children:e.jsx(x,{value:s.boltNew})})}),e.jsx("td",{className:"px-4 py-2.5 text-center",children:e.jsx("div",{className:"flex justify-center",children:e.jsx(x,{value:s.replit})})}),e.jsx("td",{className:"px-4 py-2.5 text-center",children:e.jsx("div",{className:"flex justify-center",children:e.jsx(x,{value:s.lovable})})})]},s.feature))]}))})]})})}),e.jsxs("div",{className:"mt-12",children:[e.jsx("h2",{className:"text-xl font-bold text-[#36342E] mb-6",children:"Why developers choose Loki Mode"}),e.jsx("div",{className:"grid grid-cols-1 md:grid-cols-2 gap-5",children:k.map(t=>e.jsxs("div",{className:"bg-white border border-[#ECEAE3] rounded-xl p-5 shadow-sm hover:shadow-md transition-shadow",children:[e.jsx("div",{className:"mb-3",children:t.icon}),e.jsx("h3",{className:"text-base font-bold text-[#36342E] mb-1",children:t.title}),e.jsx("p",{className:"text-sm text-[#6B6960]",children:t.description})]},t.title))})]}),e.jsx("div",{className:"mt-12 max-w-xl mx-auto",children:e.jsx(g,{})})]})})}export{C as default};
|
package/web-app/dist/assets/{EvidenceReceiptPanel-CGIK2BN5.js → EvidenceReceiptPanel-CulRYQ28.js}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{r as l,a as x,j as e}from"./index-
|
|
1
|
+
import{r as l,a as x,j as e}from"./index-CjeJkKHf.js";const N={verified:{badge:"bg-success/10 text-success border-success/20",dot:"bg-success",label:"Verified",proven:"The server recomputed the integrity hash and it matches, and the gpg signature verified against its keyring.",notProven:"That the code is correct, or that the recorded diff still matches your repo. A receipt records which checks ran, not that the result is right."},unsigned:{badge:"bg-warning/10 text-warning border-warning/20",dot:"bg-warning",label:"Unsigned",proven:"The server recomputed the integrity hash and it matches these receipt bytes.",notProven:"Who produced it. An unsigned receipt is forgeable: whoever controls the builder can rewrite the facts and recompute the hash."},unchecked:{badge:"bg-warning/10 text-warning border-warning/20",dot:"bg-warning",label:"Not checked",proven:"The server recomputed the integrity hash and it matches.",notProven:"Provenance. A signature is present but was not evaluated here, which is not the same as a bad signature."},tampered:{badge:"bg-danger/10 text-danger border-danger/20",dot:"bg-danger",label:"Tampered",proven:"Nothing. The server recomputed the integrity hash and it does not match the contents.",notProven:"Anything at all. This receipt was edited after it was written. Do not trust this build."},failed:{badge:"bg-danger/10 text-danger border-danger/20",dot:"bg-danger",label:"Failed verification",proven:"Nothing. A verification check ran on the server and said no.",notProven:"Anything the receipt claims. Read the reason below."},not_verified:{badge:"border-muted/20 text-muted",dot:"bg-muted/40",label:"Not verified here",proven:"Nothing. No verification result was computed for this receipt here.",notProven:"Integrity or provenance. Run the command below to check it yourself."}};function w(t){const n=t==null?void 0:t.integrity_check,r=t==null?void 0:t.verification;return n?n.status==="tampered"?"tampered":n.status==="failed"?"failed":n.status!=="verified"?"not_verified":n.gpg_ok===!0?"verified":r!=null&&r.attestation||r!=null&&r.gpg_signature?"unchecked":"unsigned":"not_verified"}const v=[{key:"verified",label:"Verified",bar:"bg-success",text:"text-success"},{key:"with_gaps",label:"With gaps",bar:"bg-warning",text:"text-warning"},{key:"not_verified",label:"Not verified",bar:"bg-danger",text:"text-danger"},{key:"unknown",label:"Unknown",bar:"bg-muted/40",text:"text-muted"}];function y({summary:t}){const n=t.total_receipts;return n?e.jsxs("div",{className:"space-y-2",children:[e.jsx("div",{className:"flex h-1.5 rounded-full overflow-hidden bg-muted/10",children:v.map(({key:r,bar:s})=>{const i=t[r];return i?e.jsx("div",{className:s,style:{width:`${i/n*100}%`},title:`${i} ${r}`},r):null})}),e.jsx("div",{className:"flex flex-wrap gap-x-4 gap-y-1 text-xs",children:v.map(({key:r,label:s,text:i})=>{const c=t[r];return c?e.jsxs("span",{className:i,children:[e.jsx("span",{className:"font-semibold",children:c})," ",s.toLowerCase()]},r):null})}),e.jsxs("p",{className:"text-muted text-xs",children:["Recorded verdicts across ",n," receipt",n===1?"":"s",", not re-verified here."]})]}):null}function u({label:t,value:n}){return e.jsxs("div",{className:"flex items-baseline gap-2 text-xs",children:[e.jsx("span",{className:"text-muted w-28 flex-shrink-0",children:t}),e.jsx("span",{className:"font-mono truncate",title:n,children:n})]})}function k({proof:t}){var m,p,g,f,b;const[n,r]=l.useState(!1),[s,i]=l.useState(null),[c,d]=l.useState(null);l.useEffect(()=>{if(!n||s||c)return;let o=!1;return x.getProof(t.run_id).then(h=>{o||i(h)}).catch(h=>{o||d((h==null?void 0:h.message)||"could not load this receipt")}),()=>{o=!0}},[n,t.run_id,s,c]);const a=N[w(s)],j=t.generated_at?new Date(t.generated_at).toLocaleString():"unknown";return e.jsxs("div",{className:`border rounded-card overflow-hidden ${s?a.badge:"border-muted/20"}`,children:[e.jsxs("button",{type:"button",className:"w-full flex items-center gap-3 px-3 py-2.5 text-left",onClick:()=>r(!n),"aria-expanded":n,children:[e.jsx("span",{className:`w-2 h-2 rounded-full flex-shrink-0 ${s?a.dot:"bg-muted/40"}`}),e.jsx("span",{className:"text-sm font-medium flex-1 truncate",children:t.headline?`Recorded: ${t.headline}`:t.run_id}),t.final_verdict&&e.jsxs("span",{className:"text-xs font-mono uppercase tracking-wider flex-shrink-0 text-muted",children:["council ",t.final_verdict]}),e.jsx("span",{className:"text-muted text-xs flex-shrink-0",children:n?"−":"+"})]}),n&&e.jsxs("div",{className:"px-3 pb-3 space-y-3 border-t border-current/10 pt-3",children:[c&&e.jsxs("p",{className:"text-xs text-danger",children:["Could not load this receipt: ",c]}),!c&&!s&&e.jsx("p",{className:"text-xs text-muted",children:"Loading receipt…"}),s&&e.jsxs(e.Fragment,{children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx(u,{label:"Run",value:s.run_id}),e.jsx(u,{label:"Generated",value:j}),e.jsx(u,{label:"Loki version",value:s.loki_version||"unknown"}),e.jsx(u,{label:"Cost",value:typeof((m=s.cost)==null?void 0:m.usd)=="number"?`${s.cost.cost_partial===!0?"at least ":""}$${s.cost.usd.toFixed(2)}`:"unknown"}),e.jsx(u,{label:"Files changed",value:typeof((p=s.files_changed)==null?void 0:p.count)=="number"?String(s.files_changed.count):"unknown"}),((g=s.verification)==null?void 0:g.hash)&&e.jsx(u,{label:"Recorded hash",value:s.verification.hash})]}),e.jsxs("div",{className:`rounded-card border px-3 py-2 ${a.badge}`,children:[e.jsx("p",{className:"text-xs font-semibold uppercase tracking-wider mb-1",children:a.label}),e.jsxs("p",{className:"text-xs mb-1",children:[e.jsx("span",{className:"font-semibold",children:"Proven: "}),a.proven]}),e.jsxs("p",{className:"text-xs opacity-80",children:[e.jsx("span",{className:"font-semibold",children:"Not proven: "}),a.notProven]}),(((f=s.integrity_check)==null?void 0:f.reasons)||[]).slice(0,2).map(o=>e.jsx("p",{className:"text-xs opacity-80 mt-1",children:o},o))]}),e.jsxs("p",{className:"text-xs text-muted",children:["Verify it yourself (also re-derives the diff against your repo):"," ",e.jsxs("code",{className:"font-mono",children:["loki proof verify ",s.run_id,(b=s.verification)!=null&&b.attestation?" --jwks <url|file>":""]})]}),t.pr_url&&e.jsx("a",{href:t.pr_url,target:"_blank",rel:"noreferrer noopener",className:"text-xs text-primary underline",children:"View the pull request"})]})]})]})}function P(){const[t,n]=l.useState(null),[r,s]=l.useState(null),[i,c]=l.useState(null);return l.useEffect(()=>{let d=!1;return x.listProofs().then(a=>{d||n(a.proofs||[])}).catch(a=>{d||c((a==null?void 0:a.message)||"could not load receipts")}),x.proofsSummary().then(a=>{d||s(a)}).catch(()=>{}),()=>{d=!0}},[]),e.jsxs("section",{className:"space-y-3",children:[e.jsxs("div",{children:[e.jsx("h2",{className:"text-sm font-semibold",children:"Evidence Receipts"}),e.jsx("p",{className:"text-muted text-xs mt-1",children:"What each build actually checked, recorded so you can verify it yourself."})]}),i&&e.jsxs("p",{className:"text-xs text-danger",children:["Could not load receipts: ",i]}),!i&&t===null&&e.jsx("p",{className:"text-xs text-muted",children:"Loading…"}),r&&e.jsx(y,{summary:r}),t!==null&&t.length===0&&e.jsxs("p",{className:"text-xs text-muted",children:["No receipts yet. One is written at the end of each run (set ",e.jsx("code",{className:"font-mono",children:"LOKI_PROOF=0"})," to opt out)."]}),e.jsx("div",{className:"space-y-2",children:t==null?void 0:t.map(d=>e.jsx(k,{proof:d},d.run_id))})]})}export{P as E};
|