loki-mode 7.34.1 → 7.35.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/README.md +1 -1
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/dashboard/__init__.py +1 -1
- package/dashboard/static/index.html +90 -10
- package/docs/INSTALLATION.md +1 -1
- package/loki-ts/dist/loki.js +2 -2
- package/mcp/__init__.py +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
[](https://www.npmjs.com/package/loki-mode)
|
|
10
10
|
[](https://www.npmjs.com/package/loki-mode)
|
|
11
|
-
[](https://github.com/asklokesh/loki-mode/stargazers)
|
|
12
12
|
[](https://hub.docker.com/r/asklokesh/loki-mode)
|
|
13
13
|
[](LICENSE)
|
|
14
14
|
|
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, 11 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.
|
|
6
|
+
# Loki Mode v7.35.0
|
|
7
7
|
|
|
8
8
|
**You are an autonomous agent. You make decisions. You do not ask questions. You do not stop.**
|
|
9
9
|
|
|
@@ -398,4 +398,4 @@ See `CHANGELOG.md` entries [7.5.7], [7.5.8], [7.5.13] for the per-fix list and r
|
|
|
398
398
|
|
|
399
399
|
---
|
|
400
400
|
|
|
401
|
-
**v7.
|
|
401
|
+
**v7.35.0 | [Autonomi](https://www.autonomi.dev/) flagship product | ~260 lines core**
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
7.
|
|
1
|
+
7.35.0
|
package/dashboard/__init__.py
CHANGED
|
@@ -329,6 +329,27 @@
|
|
|
329
329
|
text-overflow: ellipsis;
|
|
330
330
|
white-space: nowrap;
|
|
331
331
|
}
|
|
332
|
+
/* v7.35: the chip name is a switch-project affordance. Clickable names get
|
|
333
|
+
a pointer + hover accent; the active project's name is emphasized and
|
|
334
|
+
not clickable (already focused). */
|
|
335
|
+
.project-stop-row .project-stop-name.is-clickable {
|
|
336
|
+
cursor: pointer;
|
|
337
|
+
border-radius: 6px;
|
|
338
|
+
padding: 0 2px;
|
|
339
|
+
transition: color 0.12s ease, background 0.12s ease;
|
|
340
|
+
}
|
|
341
|
+
.project-stop-row .project-stop-name.is-clickable:hover {
|
|
342
|
+
color: var(--loki-accent, #553DE9);
|
|
343
|
+
background: var(--loki-bg-hover, rgba(85, 61, 233, 0.08));
|
|
344
|
+
}
|
|
345
|
+
.project-stop-row .project-stop-name.is-clickable:focus-visible {
|
|
346
|
+
outline: 2px solid var(--loki-accent, #553DE9);
|
|
347
|
+
outline-offset: 1px;
|
|
348
|
+
}
|
|
349
|
+
.project-stop-row .project-stop-name.is-active {
|
|
350
|
+
font-weight: 600;
|
|
351
|
+
color: var(--loki-accent, #553DE9);
|
|
352
|
+
}
|
|
332
353
|
.project-stop-row button {
|
|
333
354
|
padding: 2px 8px;
|
|
334
355
|
background: transparent;
|
|
@@ -13799,6 +13820,16 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
|
13799
13820
|
var sel = document.getElementById('project-switcher');
|
|
13800
13821
|
if (!sel) return;
|
|
13801
13822
|
var stopList = document.getElementById('project-stop-list');
|
|
13823
|
+
// v7.35: focus a project by its working dir, then reload so every panel
|
|
13824
|
+
// re-fetches against it. The active section lives in the URL hash now, so
|
|
13825
|
+
// the reload lands the user on the SAME section (no reset to overview).
|
|
13826
|
+
// Shared by the dropdown <select> and the clickable project chips.
|
|
13827
|
+
function focusProject(dir) {
|
|
13828
|
+
var req = dir
|
|
13829
|
+
? fetch('/api/focus', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ project_dir: dir }) })
|
|
13830
|
+
: fetch('/api/focus', { method: 'DELETE' });
|
|
13831
|
+
return req.then(function(){ window.location.reload(); }).catch(function(){ /* ignore */ });
|
|
13832
|
+
}
|
|
13802
13833
|
// v7.7.30: build a per-row Stop control for each running project using
|
|
13803
13834
|
// createElement + textContent only (never innerHTML for project-supplied
|
|
13804
13835
|
// strings), so a project name can never inject markup.
|
|
@@ -13812,6 +13843,24 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
|
13812
13843
|
var name = document.createElement('span');
|
|
13813
13844
|
name.className = 'project-stop-name';
|
|
13814
13845
|
name.textContent = p.name || p.path || 'project';
|
|
13846
|
+
// v7.35: the chip name is now a clickable affordance that focuses
|
|
13847
|
+
// that project (same path as the dropdown). The Stop button keeps its
|
|
13848
|
+
// own handler; clicking the name never triggers Stop. is_active chips
|
|
13849
|
+
// are marked so the current project is visually obvious and its click
|
|
13850
|
+
// is a no-op (already focused).
|
|
13851
|
+
if (p.is_active) {
|
|
13852
|
+
name.classList.add('is-active');
|
|
13853
|
+
} else if (p.path) {
|
|
13854
|
+
name.classList.add('is-clickable');
|
|
13855
|
+
name.setAttribute('role', 'button');
|
|
13856
|
+
name.setAttribute('tabindex', '0');
|
|
13857
|
+
name.setAttribute('title', 'Switch to ' + (p.name || p.path));
|
|
13858
|
+
var go = function(ev){ if (ev) ev.stopPropagation(); focusProject(p.path); };
|
|
13859
|
+
name.addEventListener('click', go);
|
|
13860
|
+
name.addEventListener('keydown', function(ev){
|
|
13861
|
+
if (ev.key === 'Enter' || ev.key === ' ') { ev.preventDefault(); go(ev); }
|
|
13862
|
+
});
|
|
13863
|
+
}
|
|
13815
13864
|
var btn = document.createElement('button');
|
|
13816
13865
|
btn.type = 'button';
|
|
13817
13866
|
btn.textContent = 'Stop';
|
|
@@ -13858,14 +13907,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
|
13858
13907
|
.catch(function(){ /* offline / no endpoint: leave as-is */ });
|
|
13859
13908
|
}
|
|
13860
13909
|
sel.addEventListener('change', function(){
|
|
13861
|
-
|
|
13862
|
-
var req = dir
|
|
13863
|
-
? fetch('/api/focus', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ project_dir: dir }) })
|
|
13864
|
-
: fetch('/api/focus', { method: 'DELETE' });
|
|
13865
|
-
req.then(function(){
|
|
13866
|
-
// Reload so every panel re-fetches against the newly focused project.
|
|
13867
|
-
window.location.reload();
|
|
13868
|
-
}).catch(function(){ /* ignore */ });
|
|
13910
|
+
focusProject(sel.value);
|
|
13869
13911
|
});
|
|
13870
13912
|
refresh();
|
|
13871
13913
|
setInterval(refresh, 15000);
|
|
@@ -14091,6 +14133,17 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
|
14091
14133
|
// Scroll main content to top on section switch
|
|
14092
14134
|
mainContent.scrollTop = 0;
|
|
14093
14135
|
localStorage.setItem('loki-active-section', sectionId);
|
|
14136
|
+
// v7.35: reflect the active section in the URL hash so a refresh,
|
|
14137
|
+
// back-button, or a project switch (which reloads the page) lands the
|
|
14138
|
+
// user back on the SAME section instead of resetting to overview. The
|
|
14139
|
+
// hash is updated in place (replaceState) so it does not stack history
|
|
14140
|
+
// entries on every tab click.
|
|
14141
|
+
try {
|
|
14142
|
+
var nh = '#section=' + sectionId;
|
|
14143
|
+
if (window.location.hash !== nh) {
|
|
14144
|
+
history.replaceState(null, '', window.location.pathname + window.location.search + nh);
|
|
14145
|
+
}
|
|
14146
|
+
} catch (e) { /* file:// or sandboxed: hash routing best-effort */ }
|
|
14094
14147
|
}
|
|
14095
14148
|
|
|
14096
14149
|
navLinks.forEach(function(link) {
|
|
@@ -14103,8 +14156,35 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
|
14103
14156
|
});
|
|
14104
14157
|
});
|
|
14105
14158
|
|
|
14106
|
-
//
|
|
14107
|
-
|
|
14159
|
+
// v7.35: restore the active section on load. Priority: URL hash
|
|
14160
|
+
// (#section=<id>, shareable + survives the project-switch reload) ->
|
|
14161
|
+
// localStorage (last-used on this machine) -> overview (default). Only
|
|
14162
|
+
// honor a section id that maps to a real nav link, so a stale/hand-edited
|
|
14163
|
+
// hash can never blank the page.
|
|
14164
|
+
function lokiInitialSection() {
|
|
14165
|
+
var fromHash = '';
|
|
14166
|
+
try {
|
|
14167
|
+
var m = (window.location.hash || '').match(/section=([A-Za-z0-9_-]+)/);
|
|
14168
|
+
if (m) fromHash = m[1];
|
|
14169
|
+
} catch (e) { /* ignore */ }
|
|
14170
|
+
var fromStore = '';
|
|
14171
|
+
try { fromStore = localStorage.getItem('loki-active-section') || ''; } catch (e) { /* ignore */ }
|
|
14172
|
+
var candidate = fromHash || fromStore || 'overview';
|
|
14173
|
+
if (!document.querySelector('.nav-link[data-section="' + candidate + '"]')) {
|
|
14174
|
+
candidate = 'overview';
|
|
14175
|
+
}
|
|
14176
|
+
return candidate;
|
|
14177
|
+
}
|
|
14178
|
+
switchSection(lokiInitialSection());
|
|
14179
|
+
|
|
14180
|
+
// Keep the view in sync if the hash changes (back/forward button, or a
|
|
14181
|
+
// shared link opened in the same tab).
|
|
14182
|
+
window.addEventListener('hashchange', function() {
|
|
14183
|
+
var m = (window.location.hash || '').match(/section=([A-Za-z0-9_-]+)/);
|
|
14184
|
+
if (m && document.querySelector('.nav-link[data-section="' + m[1] + '"]')) {
|
|
14185
|
+
switchSection(m[1]);
|
|
14186
|
+
}
|
|
14187
|
+
});
|
|
14108
14188
|
|
|
14109
14189
|
// Keyboard shortcuts: Cmd/Ctrl + 1-7
|
|
14110
14190
|
document.addEventListener('keydown', function(e) {
|
package/docs/INSTALLATION.md
CHANGED
|
@@ -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.
|
|
5
|
+
**Version:** v7.35.0
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
package/loki-ts/dist/loki.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var n6=Object.defineProperty;var a6=($)=>$;function s6($,Q){this[$]=a6.bind(null,Q)}var h=($,Q)=>{for(var Z in Q)n6($,Z,{get:Q[Z],enumerable:!0,configurable:!0,set:s6.bind(Q,Z)})};var L=($,Q)=>()=>($&&(Q=$($=0)),Q);var K$=import.meta.require;var S1={};h(S1,{lokiDir:()=>P,homeLokiDir:()=>o$,findRepoRootForVersion:()=>d$,REPO_ROOT:()=>m});import{resolve as n,dirname as l$}from"path";import{fileURLToPath as t6}from"url";import{existsSync as P$}from"fs";import{homedir as r6}from"os";function i6(){let $=N1;for(let Q=0;Q<6;Q++){if(P$(n($,"VERSION"))&&P$(n($,"autonomy/run.sh")))return $;let Z=l$($);if(Z===$)break;$=Z}return n(N1,"..","..","..")}function d$($){let Q=$;for(let Z=0;Z<6;Z++){if(P$(n(Q,"VERSION"))&&P$(n(Q,"autonomy/run.sh")))return Q;let z=l$(Q);if(z===Q)break;Q=z}return n($,"..","..","..")}function P(){return process.env.LOKI_DIR??n(process.cwd(),".loki")}function o$(){return n(r6(),".loki")}var N1,m;var C=L(()=>{N1=l$(t6(import.meta.url));m=i6()});import{readFileSync as e6}from"fs";import{resolve as $Q,dirname as QQ}from"path";import{fileURLToPath as ZQ}from"url";function F$(){if($$!==null)return $$;let $="7.
|
|
2
|
+
var n6=Object.defineProperty;var a6=($)=>$;function s6($,Q){this[$]=a6.bind(null,Q)}var h=($,Q)=>{for(var Z in Q)n6($,Z,{get:Q[Z],enumerable:!0,configurable:!0,set:s6.bind(Q,Z)})};var L=($,Q)=>()=>($&&(Q=$($=0)),Q);var K$=import.meta.require;var S1={};h(S1,{lokiDir:()=>P,homeLokiDir:()=>o$,findRepoRootForVersion:()=>d$,REPO_ROOT:()=>m});import{resolve as n,dirname as l$}from"path";import{fileURLToPath as t6}from"url";import{existsSync as P$}from"fs";import{homedir as r6}from"os";function i6(){let $=N1;for(let Q=0;Q<6;Q++){if(P$(n($,"VERSION"))&&P$(n($,"autonomy/run.sh")))return $;let Z=l$($);if(Z===$)break;$=Z}return n(N1,"..","..","..")}function d$($){let Q=$;for(let Z=0;Z<6;Z++){if(P$(n(Q,"VERSION"))&&P$(n(Q,"autonomy/run.sh")))return Q;let z=l$(Q);if(z===Q)break;Q=z}return n($,"..","..","..")}function P(){return process.env.LOKI_DIR??n(process.cwd(),".loki")}function o$(){return n(r6(),".loki")}var N1,m;var C=L(()=>{N1=l$(t6(import.meta.url));m=i6()});import{readFileSync as e6}from"fs";import{resolve as $Q,dirname as QQ}from"path";import{fileURLToPath as ZQ}from"url";function F$(){if($$!==null)return $$;let $="7.35.0";if(typeof $==="string"&&$.length>0)return $$=$,$$;try{let Q=QQ(ZQ(import.meta.url)),Z=d$(Q);$$=e6($Q(Z,"VERSION"),"utf-8").trim()}catch{$$="unknown"}return $$}var $$=null;var n$=L(()=>{C()});var C1={};h(C1,{runOrThrow:()=>zQ,run:()=>j,commandVersion:()=>KQ,commandExists:()=>f,ShellError:()=>a$});async function j($,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[W,K,U]=await Promise.all([new Response(Z.stdout).text(),new Response(Z.stderr).text(),Z.exited]);return{stdout:W,stderr:K,exitCode:U}}finally{if(z)clearTimeout(z);if(X)clearTimeout(X)}}async function zQ($,Q={}){let Z=await j($,Q);if(Z.exitCode!==0)throw new a$(`command failed (${Z.exitCode}): ${$.join(" ")}`,Z.exitCode,Z.stdout,Z.stderr);return Z}async function f($){let Q=XQ($),Z=await j(["sh","-c",`command -v ${Q}`],{timeoutMs:5000});if(Z.exitCode===0)return Z.stdout.trim()||null;return null}function XQ($){if(!/^[A-Za-z0-9._/-]+$/.test($))throw Error(`refused to shell-escape suspect token: ${$}`);return $}async function KQ($,Q="--version"){if(!await f($))return null;let z=await j([$,Q],{timeoutMs:5000});if(z.exitCode!==0)return null;return((z.stdout||z.stderr).split(/\r?\n/)[0]?.trim()??"")||null}var a$;var d=L(()=>{a$=class a$ 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 a($){return WQ?"":$}var WQ,T,S,I,TZ,w,R,y,q;var c=L(()=>{WQ=(process.env.NO_COLOR??"").length>0;T=a("\x1B[0;31m"),S=a("\x1B[0;32m"),I=a("\x1B[1;33m"),TZ=a("\x1B[0;34m"),w=a("\x1B[0;36m"),R=a("\x1B[1m"),y=a("\x1B[2m"),q=a("\x1B[0m")});import{existsSync as TQ}from"fs";async function Q$(){if(B$!==void 0)return B$;let $="/opt/homebrew/bin/python3.12";if(TQ($))return B$=$,$;let Q=await f("python3.12");if(Q)return B$=Q,Q;let Z=await f("python3");return B$=Z,Z}async function Z$($,Q={}){let Z=await Q$();if(!Z)return{stdout:"",stderr:"python3 not found",exitCode:127};return j([Z,"-c",$],Q)}var B$;var W$=L(()=>{d()});var t1={};h(t1,{runStatus:()=>gQ});import{existsSync as v,readFileSync as U$,readdirSync as l1,statSync as d1}from"fs";import{resolve as D,basename as xQ}from"path";import{homedir as NQ}from"os";async function DQ(){if(await f("jq"))return!0;return process.stdout.write(`${T}Error: jq is required but not installed.${q}
|
|
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)
|
|
@@ -789,4 +789,4 @@ Set LOKI_LEGACY_BASH=1 to force the bash CLI for every command.
|
|
|
789
789
|
`),2}default:return process.stderr.write(`Unknown command: ${Q}
|
|
790
790
|
`),process.stderr.write(o6),2}}p1();process.on("SIGINT",()=>process.exit(130));process.on("SIGTERM",()=>process.exit(143));var ZZ=await QZ(Bun.argv.slice(2));process.exit(ZZ);
|
|
791
791
|
|
|
792
|
-
//# debugId=
|
|
792
|
+
//# debugId=4A51F9C635720B1064756E2164756E21
|
package/mcp/__init__.py
CHANGED
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.
|
|
4
|
+
"version": "7.35.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 11 quality gates. Provider-agnostic (Claude Code, OpenAI Codex, Cline, Aider).",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"agent",
|