loki-mode 7.92.0 → 7.94.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/lib/done-recognition.sh +823 -0
- package/autonomy/run.sh +74 -1
- package/dashboard/__init__.py +1 -1
- package/dashboard/server.py +179 -20
- package/dashboard/static/index.html +423 -104
- package/docs/INSTALLATION.md +2 -2
- package/docs/PRD-REUSE-DONE-RECOGNITION-PLAN.md +536 -0
- package/loki-ts/dist/loki.js +2 -2
- package/mcp/__init__.py +1 -1
- package/package.json +1 -1
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
|
@@ -134,10 +134,17 @@
|
|
|
134
134
|
font-feature-settings: 'cv02', 'cv03', 'cv04', 'cv11';
|
|
135
135
|
}
|
|
136
136
|
|
|
137
|
-
/* Dashboard Layout
|
|
137
|
+
/* Dashboard Layout. v7.92 sidebar rebalance: a THREE-column grid -- a clean
|
|
138
|
+
left navigation rail, the main content, and a collapsible right status
|
|
139
|
+
sidebar. The left column is navigation only; the system status + session
|
|
140
|
+
controls moved out of the cramped left footer into the right column so
|
|
141
|
+
both surfaces can breathe. The third track is sized by a CSS var so the
|
|
142
|
+
same rule drives expanded (288px) and collapsed (a 48px rail). */
|
|
138
143
|
.dashboard-layout {
|
|
144
|
+
--status-rail-width: 48px;
|
|
145
|
+
--status-panel-width: 288px;
|
|
139
146
|
display: grid;
|
|
140
|
-
grid-template-columns: 240px 1fr;
|
|
147
|
+
grid-template-columns: 240px 1fr var(--status-panel-width);
|
|
141
148
|
grid-template-rows: 1fr;
|
|
142
149
|
/* Pin to the viewport (not min-height) so the grid row can never grow
|
|
143
150
|
taller than the screen. With min-height the 1fr row stretched to the
|
|
@@ -150,8 +157,16 @@
|
|
|
150
157
|
overflow: hidden;
|
|
151
158
|
}
|
|
152
159
|
|
|
160
|
+
/* Collapsed: the status sidebar shrinks to a thin rail and the center
|
|
161
|
+
content reclaims the freed width. Driven by a class on the GRID (not just
|
|
162
|
+
the aside) so the track resizes in lockstep with the panel. */
|
|
163
|
+
.dashboard-layout.status-collapsed {
|
|
164
|
+
grid-template-columns: 240px 1fr var(--status-rail-width);
|
|
165
|
+
}
|
|
166
|
+
|
|
153
167
|
@media (max-width: 768px) {
|
|
154
|
-
.dashboard-layout
|
|
168
|
+
.dashboard-layout,
|
|
169
|
+
.dashboard-layout.status-collapsed {
|
|
155
170
|
grid-template-columns: 1fr;
|
|
156
171
|
}
|
|
157
172
|
.sidebar { display: none; }
|
|
@@ -162,6 +177,18 @@
|
|
|
162
177
|
width: 240px;
|
|
163
178
|
z-index: 100;
|
|
164
179
|
}
|
|
180
|
+
/* On mobile the third column would steal the whole row; collapse it to a
|
|
181
|
+
pinned rail on the right edge instead so status stays one tap away
|
|
182
|
+
without crowding the content. */
|
|
183
|
+
.status-sidebar {
|
|
184
|
+
position: fixed;
|
|
185
|
+
right: 0; top: 0; bottom: 0;
|
|
186
|
+
width: var(--status-rail-width);
|
|
187
|
+
z-index: 90;
|
|
188
|
+
}
|
|
189
|
+
.dashboard-layout:not(.status-collapsed) .status-sidebar {
|
|
190
|
+
width: min(320px, 88vw);
|
|
191
|
+
}
|
|
165
192
|
}
|
|
166
193
|
|
|
167
194
|
/* Sidebar - glass effect. v7.84 enterprise IA: a three-region flex column
|
|
@@ -352,51 +379,56 @@
|
|
|
352
379
|
flex-shrink: 0;
|
|
353
380
|
}
|
|
354
381
|
|
|
355
|
-
/*
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
382
|
+
/* (v7.92) The left sidebar footer was removed: the session control + the
|
|
383
|
+
Settings gear it used to hold moved into the right status sidebar, so the
|
|
384
|
+
left column is navigation only.
|
|
385
|
+
|
|
386
|
+
(v7.93) The Settings gear + upward-opening popover were replaced by an
|
|
387
|
+
inline collapsible disclosure that lives in the right sidebar's scrolling
|
|
388
|
+
body (.status-settings). Inline-in-flow has no anchoring/clipping/z-index
|
|
389
|
+
failure modes, is keyboard-accessible, and matches the collapsible-sidebar
|
|
390
|
+
design language. The disclosure header is a real button (aria-expanded +
|
|
391
|
+
aria-controls); the region is hidden from the tab order while collapsed. */
|
|
392
|
+
|
|
393
|
+
/* Inline Settings disclosure (right-sidebar, in-flow). */
|
|
394
|
+
.status-settings {
|
|
362
395
|
flex: 0 0 auto;
|
|
396
|
+
border: 1px solid var(--loki-border);
|
|
397
|
+
border-radius: 8px;
|
|
398
|
+
background: var(--loki-bg-tertiary);
|
|
399
|
+
overflow: hidden;
|
|
363
400
|
}
|
|
364
401
|
|
|
365
|
-
|
|
402
|
+
/* Disclosure header: a full-width real button. The chevron rotates to point
|
|
403
|
+
down when the section is open. */
|
|
404
|
+
.settings-disclosure {
|
|
366
405
|
display: flex;
|
|
367
|
-
gap: 6px;
|
|
368
406
|
align-items: center;
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
gap: 6px;
|
|
378
|
-
padding: 6px 10px;
|
|
379
|
-
background: var(--loki-bg-tertiary);
|
|
380
|
-
border: 1px solid var(--loki-border);
|
|
381
|
-
border-radius: 7px;
|
|
407
|
+
gap: 8px;
|
|
408
|
+
width: 100%;
|
|
409
|
+
box-sizing: border-box;
|
|
410
|
+
padding: 9px 11px;
|
|
411
|
+
background: transparent;
|
|
412
|
+
border: none;
|
|
413
|
+
border-radius: 8px;
|
|
414
|
+
font-family: 'Inter', system-ui, sans-serif;
|
|
382
415
|
font-size: 11px;
|
|
416
|
+
font-weight: 600;
|
|
417
|
+
text-transform: uppercase;
|
|
418
|
+
letter-spacing: 0.06em;
|
|
383
419
|
color: var(--loki-text-secondary);
|
|
384
420
|
cursor: pointer;
|
|
385
|
-
transition:
|
|
386
|
-
font-family: inherit;
|
|
421
|
+
transition: background var(--loki-transition), color var(--loki-transition);
|
|
387
422
|
}
|
|
388
|
-
|
|
389
|
-
.footer-btn:hover {
|
|
423
|
+
.settings-disclosure:hover {
|
|
390
424
|
background: var(--loki-bg-hover);
|
|
391
425
|
color: var(--loki-text-primary);
|
|
392
426
|
}
|
|
393
|
-
|
|
394
|
-
.footer-btn:focus-visible {
|
|
427
|
+
.settings-disclosure:focus-visible {
|
|
395
428
|
outline: 2px solid var(--loki-accent);
|
|
396
|
-
outline-offset:
|
|
429
|
+
outline-offset: -2px;
|
|
397
430
|
}
|
|
398
|
-
|
|
399
|
-
.footer-btn svg {
|
|
431
|
+
.settings-disclosure svg {
|
|
400
432
|
width: 14px;
|
|
401
433
|
height: 14px;
|
|
402
434
|
stroke: currentColor;
|
|
@@ -404,31 +436,56 @@
|
|
|
404
436
|
fill: none;
|
|
405
437
|
flex-shrink: 0;
|
|
406
438
|
}
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
439
|
+
.settings-disclosure .settings-gear {
|
|
440
|
+
margin-right: 2px;
|
|
441
|
+
}
|
|
442
|
+
.settings-disclosure .settings-chevron {
|
|
443
|
+
margin-left: auto;
|
|
444
|
+
transition: transform var(--loki-transition);
|
|
445
|
+
}
|
|
446
|
+
.settings-disclosure[aria-expanded="true"] .settings-chevron {
|
|
447
|
+
transform: rotate(90deg);
|
|
411
448
|
}
|
|
412
449
|
|
|
413
|
-
/*
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
box-shadow: var(--loki-glass-shadow);
|
|
426
|
-
z-index: 50;
|
|
450
|
+
/* Collapsible region. Uses the grid 0fr/1fr trick for a smooth height
|
|
451
|
+
transition; the inner wrapper is the actual clipping box. While collapsed
|
|
452
|
+
the region carries the [hidden] attribute (set by JS). We override the
|
|
453
|
+
default display:none [hidden] gives so the height can animate, but pair it
|
|
454
|
+
with visibility:hidden on the inner wrapper, which removes the input + Go
|
|
455
|
+
button from the tab order while collapsed (a plain 0fr collapse would
|
|
456
|
+
leave them tab-focusable). visibility is delayed on collapse and reset on
|
|
457
|
+
expand so the controls are reachable exactly when the section is open. */
|
|
458
|
+
.settings-region {
|
|
459
|
+
display: grid;
|
|
460
|
+
grid-template-rows: 1fr;
|
|
461
|
+
transition: grid-template-rows var(--loki-transition);
|
|
427
462
|
}
|
|
428
|
-
.settings-
|
|
429
|
-
display:
|
|
463
|
+
.settings-region[hidden] {
|
|
464
|
+
display: grid;
|
|
465
|
+
grid-template-rows: 0fr;
|
|
466
|
+
}
|
|
467
|
+
.settings-region-inner {
|
|
468
|
+
overflow: hidden;
|
|
469
|
+
min-height: 0;
|
|
470
|
+
visibility: visible;
|
|
471
|
+
transition: visibility 0s linear 0s;
|
|
472
|
+
}
|
|
473
|
+
.settings-region[hidden] .settings-region-inner {
|
|
474
|
+
visibility: hidden;
|
|
475
|
+
transition: visibility 0s linear 0.2s;
|
|
476
|
+
}
|
|
477
|
+
@media (prefers-reduced-motion: reduce) {
|
|
478
|
+
.settings-region[hidden] .settings-region-inner { transition: none; }
|
|
430
479
|
}
|
|
431
|
-
.settings-
|
|
480
|
+
.settings-region-body {
|
|
481
|
+
padding: 4px 11px 11px;
|
|
482
|
+
}
|
|
483
|
+
@media (prefers-reduced-motion: reduce) {
|
|
484
|
+
.settings-region { transition: none; }
|
|
485
|
+
.settings-disclosure .settings-chevron { transition: none; }
|
|
486
|
+
}
|
|
487
|
+
.settings-field-label {
|
|
488
|
+
display: block;
|
|
432
489
|
font-size: 9.5px;
|
|
433
490
|
font-weight: 600;
|
|
434
491
|
text-transform: uppercase;
|
|
@@ -436,7 +493,7 @@
|
|
|
436
493
|
color: var(--loki-text-muted);
|
|
437
494
|
margin-bottom: 6px;
|
|
438
495
|
}
|
|
439
|
-
.settings-
|
|
496
|
+
.settings-field-row {
|
|
440
497
|
display: flex;
|
|
441
498
|
gap: 6px;
|
|
442
499
|
align-items: center;
|
|
@@ -610,6 +667,147 @@
|
|
|
610
667
|
cursor: default;
|
|
611
668
|
}
|
|
612
669
|
|
|
670
|
+
/* Right status sidebar (v7.92). Mirrors the left sidebar's glass treatment
|
|
671
|
+
and three-region flex column (anchored header + scrolling body), but on
|
|
672
|
+
the right edge and collapsible. It owns its own scroll (min-height:0 +
|
|
673
|
+
overflow-y:auto on the body) so the tall status panel can never grow the
|
|
674
|
+
grid row and reintroduce the window-scroll bug documented above. */
|
|
675
|
+
.status-sidebar {
|
|
676
|
+
display: flex;
|
|
677
|
+
flex-direction: column;
|
|
678
|
+
background: var(--loki-glass-bg);
|
|
679
|
+
backdrop-filter: blur(16px) saturate(1.4);
|
|
680
|
+
-webkit-backdrop-filter: blur(16px) saturate(1.4);
|
|
681
|
+
border-left: 1px solid var(--loki-glass-border);
|
|
682
|
+
overflow: hidden;
|
|
683
|
+
min-height: 0;
|
|
684
|
+
height: 100vh;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
/* Anchored header: a small label + the collapse toggle. Does not scroll. */
|
|
688
|
+
.status-header {
|
|
689
|
+
display: flex;
|
|
690
|
+
align-items: center;
|
|
691
|
+
justify-content: space-between;
|
|
692
|
+
gap: 8px;
|
|
693
|
+
padding: 16px 14px 12px;
|
|
694
|
+
flex: 0 0 auto;
|
|
695
|
+
border-bottom: 1px solid var(--loki-border-light);
|
|
696
|
+
}
|
|
697
|
+
.status-header-title {
|
|
698
|
+
font-family: 'Inter', system-ui, sans-serif;
|
|
699
|
+
font-size: 10px;
|
|
700
|
+
font-weight: 600;
|
|
701
|
+
text-transform: uppercase;
|
|
702
|
+
letter-spacing: 0.09em;
|
|
703
|
+
color: var(--loki-text-muted);
|
|
704
|
+
white-space: nowrap;
|
|
705
|
+
overflow: hidden;
|
|
706
|
+
text-overflow: ellipsis;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
/* Collapse/expand toggle: a small square icon button. The chevron points
|
|
710
|
+
right when expanded (click to collapse) and is swapped in the rail. */
|
|
711
|
+
.status-toggle {
|
|
712
|
+
display: inline-flex;
|
|
713
|
+
align-items: center;
|
|
714
|
+
justify-content: center;
|
|
715
|
+
width: 28px;
|
|
716
|
+
height: 28px;
|
|
717
|
+
flex: 0 0 auto;
|
|
718
|
+
padding: 0;
|
|
719
|
+
background: var(--loki-bg-tertiary);
|
|
720
|
+
border: 1px solid var(--loki-border);
|
|
721
|
+
border-radius: 7px;
|
|
722
|
+
color: var(--loki-text-secondary);
|
|
723
|
+
cursor: pointer;
|
|
724
|
+
transition: background var(--loki-transition), color var(--loki-transition);
|
|
725
|
+
}
|
|
726
|
+
.status-toggle:hover {
|
|
727
|
+
background: var(--loki-bg-hover);
|
|
728
|
+
color: var(--loki-text-primary);
|
|
729
|
+
}
|
|
730
|
+
.status-toggle:focus-visible {
|
|
731
|
+
outline: 2px solid var(--loki-accent);
|
|
732
|
+
outline-offset: 1px;
|
|
733
|
+
}
|
|
734
|
+
.status-toggle svg {
|
|
735
|
+
width: 15px;
|
|
736
|
+
height: 15px;
|
|
737
|
+
stroke: currentColor;
|
|
738
|
+
stroke-width: 2;
|
|
739
|
+
fill: none;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
/* Scrolling body: holds the session-control component + the settings gear.
|
|
743
|
+
The only scroller in this column. */
|
|
744
|
+
.status-body {
|
|
745
|
+
flex: 1 1 auto;
|
|
746
|
+
min-height: 0;
|
|
747
|
+
overflow-y: auto;
|
|
748
|
+
overflow-x: hidden;
|
|
749
|
+
padding: 12px;
|
|
750
|
+
display: flex;
|
|
751
|
+
flex-direction: column;
|
|
752
|
+
gap: 10px;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
/* Collapsed state: hide the expanded body AND the whole header (its collapse
|
|
756
|
+
chevron is meaningless once collapsed); the rail becomes the sole
|
|
757
|
+
affordance, so there is never a redundant pair of chevrons. */
|
|
758
|
+
.dashboard-layout.status-collapsed .status-body,
|
|
759
|
+
.dashboard-layout.status-collapsed .status-header {
|
|
760
|
+
display: none;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
/* Collapsed rail: a thin vertical strip with the expand affordance and a
|
|
764
|
+
single glanceable live/connected dot. Hidden while expanded. */
|
|
765
|
+
.status-rail {
|
|
766
|
+
display: none;
|
|
767
|
+
flex-direction: column;
|
|
768
|
+
align-items: center;
|
|
769
|
+
gap: 14px;
|
|
770
|
+
padding: 14px 0;
|
|
771
|
+
flex: 1 1 auto;
|
|
772
|
+
min-height: 0;
|
|
773
|
+
}
|
|
774
|
+
.dashboard-layout.status-collapsed .status-rail {
|
|
775
|
+
display: flex;
|
|
776
|
+
}
|
|
777
|
+
.status-rail-label {
|
|
778
|
+
writing-mode: vertical-rl;
|
|
779
|
+
text-orientation: mixed;
|
|
780
|
+
font-family: 'Inter', system-ui, sans-serif;
|
|
781
|
+
font-size: 9.5px;
|
|
782
|
+
font-weight: 600;
|
|
783
|
+
text-transform: uppercase;
|
|
784
|
+
letter-spacing: 0.12em;
|
|
785
|
+
color: var(--loki-text-muted);
|
|
786
|
+
user-select: none;
|
|
787
|
+
}
|
|
788
|
+
/* Live dot on the rail. Reflects connection state via a class set by JS that
|
|
789
|
+
reads the shared API client (see initStatusSidebar). Never a static dot
|
|
790
|
+
implying liveness it does not have. */
|
|
791
|
+
.status-rail-dot {
|
|
792
|
+
width: 8px;
|
|
793
|
+
height: 8px;
|
|
794
|
+
border-radius: 50%;
|
|
795
|
+
background: var(--loki-text-muted);
|
|
796
|
+
flex: 0 0 auto;
|
|
797
|
+
}
|
|
798
|
+
.status-rail-dot.connected {
|
|
799
|
+
background: var(--loki-success);
|
|
800
|
+
animation: pulse 2s infinite;
|
|
801
|
+
}
|
|
802
|
+
@media (prefers-reduced-motion: reduce) {
|
|
803
|
+
.status-rail-dot.connected { animation: none; }
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
/* (v7.93) The anchored .status-footer that held the settings gear + its
|
|
807
|
+
upward-opening popover was removed: Settings is now an inline disclosure
|
|
808
|
+
inside the scrolling .status-body, so there is no separate footer to
|
|
809
|
+
anchor or hide on collapse. */
|
|
810
|
+
|
|
613
811
|
/* Main Content */
|
|
614
812
|
.main-content {
|
|
615
813
|
padding: 28px 32px;
|
|
@@ -927,28 +1125,10 @@
|
|
|
927
1125
|
</div>
|
|
928
1126
|
</nav>
|
|
929
1127
|
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
popover so it no longer clutters the always-visible footer. -->
|
|
935
|
-
<div class="footer-settings">
|
|
936
|
-
<button class="footer-btn" id="settings-btn" type="button" title="Settings" aria-label="Settings" aria-haspopup="true" aria-expanded="false">
|
|
937
|
-
<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 11-2.83 2.83l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 11-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 11-2.83-2.83l.06-.06a1.65 1.65 0 00.33-1.82 1.65 1.65 0 00-1.51-1H3a2 2 0 110-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 112.83-2.83l.06.06a1.65 1.65 0 001.82.33H9a1.65 1.65 0 001-1.51V3a2 2 0 114 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 112.83 2.83l-.06.06a1.65 1.65 0 00-.33 1.82V9a1.65 1.65 0 001.51 1H21a2 2 0 110 4h-.09a1.65 1.65 0 00-1.51 1z"/></svg>
|
|
938
|
-
<span>Settings</span>
|
|
939
|
-
</button>
|
|
940
|
-
<div class="settings-popover" id="settings-popover" role="dialog" aria-label="Settings">
|
|
941
|
-
<div class="settings-popover-label">API URL</div>
|
|
942
|
-
<div class="settings-popover-row">
|
|
943
|
-
<input type="text" class="api-url-input" id="api-url" placeholder="API URL">
|
|
944
|
-
<button class="api-btn" id="connect-btn" type="button">Go</button>
|
|
945
|
-
</div>
|
|
946
|
-
</div>
|
|
947
|
-
</div>
|
|
948
|
-
<!-- v7.90.1: dark mode removed (light-only). The theme toggle and its
|
|
949
|
-
handler are gone; the dashboard ships a single light theme. -->
|
|
950
|
-
</div>
|
|
951
|
-
</div>
|
|
1128
|
+
<!-- v7.92 sidebar rebalance: the system status + session controls moved
|
|
1129
|
+
out of this left footer into a dedicated, collapsible RIGHT sidebar
|
|
1130
|
+
(#status-sidebar) so the left column is clean navigation that can
|
|
1131
|
+
breathe. The settings gear moved with them. -->
|
|
952
1132
|
</aside>
|
|
953
1133
|
|
|
954
1134
|
<!-- Main Content -->
|
|
@@ -1414,6 +1594,67 @@
|
|
|
1414
1594
|
<loki-wiki-browser id="wiki-browser"></loki-wiki-browser>
|
|
1415
1595
|
</div>
|
|
1416
1596
|
</main>
|
|
1597
|
+
|
|
1598
|
+
<!-- v7.92 Right status sidebar: system status + session controls, moved out
|
|
1599
|
+
of the cramped left footer. Collapsible (state remembered per machine;
|
|
1600
|
+
default expanded). Collapsed -> a thin rail with an expand affordance
|
|
1601
|
+
and a single live/connected dot, so the info is never lost. -->
|
|
1602
|
+
<aside class="status-sidebar" id="status-sidebar" aria-label="System status and session controls">
|
|
1603
|
+
<div class="status-header">
|
|
1604
|
+
<span class="status-header-title">Session</span>
|
|
1605
|
+
<button class="status-toggle" id="status-toggle" type="button"
|
|
1606
|
+
aria-controls="status-sidebar" aria-expanded="true"
|
|
1607
|
+
title="Collapse status panel" aria-label="Collapse status panel">
|
|
1608
|
+
<svg viewBox="0 0 24 24" aria-hidden="true"><polyline points="9 18 15 12 9 6"/></svg>
|
|
1609
|
+
</button>
|
|
1610
|
+
</div>
|
|
1611
|
+
|
|
1612
|
+
<!-- Expanded body: the intact session-control component (status rows,
|
|
1613
|
+
Pause/Stop, model selector, Connected/version, agent/task counts) plus
|
|
1614
|
+
the inline Settings disclosure. Its API/polling wiring is preserved by
|
|
1615
|
+
moving the element whole. -->
|
|
1616
|
+
<div class="status-body">
|
|
1617
|
+
<loki-session-control id="session-control"></loki-session-control>
|
|
1618
|
+
|
|
1619
|
+
<!-- Settings: an inline collapsible disclosure (replaces the former
|
|
1620
|
+
floating gear popover, which mis-anchored in this column). The
|
|
1621
|
+
header is a real button driving aria-expanded + aria-controls; the
|
|
1622
|
+
region is [hidden] while collapsed so the API controls stay out of
|
|
1623
|
+
the tab order. Default collapsed - the API override is rarely used. -->
|
|
1624
|
+
<div class="status-settings">
|
|
1625
|
+
<button class="settings-disclosure" id="settings-disclosure" type="button"
|
|
1626
|
+
aria-expanded="false" aria-controls="settings-region">
|
|
1627
|
+
<svg class="settings-gear" viewBox="0 0 24 24" aria-hidden="true"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 11-2.83 2.83l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 11-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 11-2.83-2.83l.06-.06a1.65 1.65 0 00.33-1.82 1.65 1.65 0 00-1.51-1H3a2 2 0 110-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 112.83-2.83l.06.06a1.65 1.65 0 001.82.33H9a1.65 1.65 0 001-1.51V3a2 2 0 114 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 112.83 2.83l-.06.06a1.65 1.65 0 00-.33 1.82V9a1.65 1.65 0 001.51 1H21a2 2 0 110 4h-.09a1.65 1.65 0 00-1.51 1z"/></svg>
|
|
1628
|
+
<span>Settings</span>
|
|
1629
|
+
<svg class="settings-chevron" viewBox="0 0 24 24" aria-hidden="true"><polyline points="9 6 15 12 9 18"/></svg>
|
|
1630
|
+
</button>
|
|
1631
|
+
<div class="settings-region" id="settings-region" hidden>
|
|
1632
|
+
<div class="settings-region-inner">
|
|
1633
|
+
<div class="settings-region-body">
|
|
1634
|
+
<label class="settings-field-label" for="api-url">API URL</label>
|
|
1635
|
+
<div class="settings-field-row">
|
|
1636
|
+
<input type="text" class="api-url-input" id="api-url" placeholder="API URL">
|
|
1637
|
+
<button class="api-btn" id="connect-btn" type="button">Go</button>
|
|
1638
|
+
</div>
|
|
1639
|
+
</div>
|
|
1640
|
+
</div>
|
|
1641
|
+
</div>
|
|
1642
|
+
</div>
|
|
1643
|
+
</div>
|
|
1644
|
+
|
|
1645
|
+
<!-- Collapsed rail: shown only when the column is collapsed. The expand
|
|
1646
|
+
button + a vertical label + a single live/connected dot wired to the
|
|
1647
|
+
shared API client (set in initStatusSidebar). -->
|
|
1648
|
+
<div class="status-rail" aria-hidden="false">
|
|
1649
|
+
<button class="status-toggle" id="status-expand" type="button"
|
|
1650
|
+
aria-controls="status-sidebar" aria-expanded="false"
|
|
1651
|
+
title="Expand status panel" aria-label="Expand status panel">
|
|
1652
|
+
<svg viewBox="0 0 24 24" aria-hidden="true"><polyline points="15 18 9 12 15 6"/></svg>
|
|
1653
|
+
</button>
|
|
1654
|
+
<span class="status-rail-dot" id="status-rail-dot" title="Connection status" role="status" aria-label="Disconnected"></span>
|
|
1655
|
+
<span class="status-rail-label" aria-hidden="true">Status</span>
|
|
1656
|
+
</div>
|
|
1657
|
+
</aside>
|
|
1417
1658
|
</div>
|
|
1418
1659
|
|
|
1419
1660
|
<!-- Keyboard Shortcuts Help Overlay -->
|
|
@@ -3609,6 +3850,10 @@ var LokiDashboard=(()=>{var He=Object.defineProperty;var _t=Object.getOwnPropert
|
|
|
3609
3850
|
|
|
3610
3851
|
.model-select {
|
|
3611
3852
|
flex: 1;
|
|
3853
|
+
/* Allow the select to shrink below its longest option's intrinsic
|
|
3854
|
+
width (the flex min-content floor) so it never overflows a narrow
|
|
3855
|
+
sidebar column; the native control ellipsizes the label. */
|
|
3856
|
+
min-width: 0;
|
|
3612
3857
|
padding: 5px 8px;
|
|
3613
3858
|
border-radius: 4px;
|
|
3614
3859
|
border: 1px solid var(--loki-border);
|
|
@@ -15211,36 +15456,110 @@ document.addEventListener('DOMContentLoaded', function() {
|
|
|
15211
15456
|
updateComponentsApiUrl(apiUrlInput.value);
|
|
15212
15457
|
});
|
|
15213
15458
|
|
|
15214
|
-
// v7.
|
|
15215
|
-
//
|
|
15216
|
-
//
|
|
15217
|
-
|
|
15218
|
-
|
|
15219
|
-
|
|
15220
|
-
|
|
15221
|
-
|
|
15222
|
-
|
|
15223
|
-
|
|
15224
|
-
|
|
15225
|
-
|
|
15226
|
-
|
|
15227
|
-
|
|
15459
|
+
// v7.93 Settings disclosure: an inline collapsible section in the right
|
|
15460
|
+
// sidebar holding the API URL override (replaces the former floating popover).
|
|
15461
|
+
// The header button drives aria-expanded; the region toggles the [hidden]
|
|
15462
|
+
// attribute (which both animates the height via CSS and removes the API
|
|
15463
|
+
// controls from the tab order while collapsed). State is remembered per
|
|
15464
|
+
// machine. Best-effort -- no-ops on an older build without the elements.
|
|
15465
|
+
(function initSettingsDisclosure() {
|
|
15466
|
+
var btn = document.getElementById('settings-disclosure');
|
|
15467
|
+
var region = document.getElementById('settings-region');
|
|
15468
|
+
if (!btn || !region) return;
|
|
15469
|
+
var STORE_KEY = 'loki-settings-expanded';
|
|
15470
|
+
|
|
15471
|
+
function apply(expanded, persist) {
|
|
15472
|
+
btn.setAttribute('aria-expanded', String(expanded));
|
|
15473
|
+
region.hidden = !expanded;
|
|
15474
|
+
if (persist) {
|
|
15475
|
+
try { localStorage.setItem(STORE_KEY, expanded ? '1' : '0'); } catch (e) { /* ignore */ }
|
|
15476
|
+
}
|
|
15228
15477
|
}
|
|
15229
|
-
|
|
15230
|
-
|
|
15231
|
-
|
|
15232
|
-
|
|
15233
|
-
|
|
15234
|
-
|
|
15235
|
-
|
|
15236
|
-
|
|
15237
|
-
if (popover.classList.contains('open')) close();
|
|
15238
|
-
});
|
|
15239
|
-
document.addEventListener('keydown', function(e) {
|
|
15240
|
-
if (e.key === 'Escape' && popover.classList.contains('open')) close();
|
|
15478
|
+
|
|
15479
|
+
var stored = null;
|
|
15480
|
+
try { stored = localStorage.getItem(STORE_KEY); } catch (e) { /* ignore */ }
|
|
15481
|
+
// Default collapsed: the API override is rarely used.
|
|
15482
|
+
apply(stored === '1', false);
|
|
15483
|
+
|
|
15484
|
+
btn.addEventListener('click', function() {
|
|
15485
|
+
apply(btn.getAttribute('aria-expanded') !== 'true', true);
|
|
15241
15486
|
});
|
|
15242
15487
|
})();
|
|
15243
15488
|
|
|
15489
|
+
// v7.92 Right status sidebar collapse. Toggled by the header chevron (when
|
|
15490
|
+
// expanded) and the rail chevron (when collapsed). State is remembered per
|
|
15491
|
+
// machine in localStorage; default is EXPANDED so nothing is hidden on first
|
|
15492
|
+
// load. Best-effort -- no-ops on an older build without the elements.
|
|
15493
|
+
(function initStatusSidebar() {
|
|
15494
|
+
var layout = document.querySelector('.dashboard-layout');
|
|
15495
|
+
var aside = document.getElementById('status-sidebar');
|
|
15496
|
+
var collapseBtn = document.getElementById('status-toggle');
|
|
15497
|
+
var expandBtn = document.getElementById('status-expand');
|
|
15498
|
+
if (!layout || !aside || !collapseBtn || !expandBtn) return;
|
|
15499
|
+
var STORE_KEY = 'loki-status-collapsed';
|
|
15500
|
+
|
|
15501
|
+
function syncAria(collapsed) {
|
|
15502
|
+
// aria-expanded describes the panel's state on whichever control is the
|
|
15503
|
+
// active affordance. Both controls point at the same panel.
|
|
15504
|
+
collapseBtn.setAttribute('aria-expanded', String(!collapsed));
|
|
15505
|
+
expandBtn.setAttribute('aria-expanded', String(!collapsed));
|
|
15506
|
+
}
|
|
15507
|
+
|
|
15508
|
+
function apply(collapsed, persist) {
|
|
15509
|
+
layout.classList.toggle('status-collapsed', collapsed);
|
|
15510
|
+
syncAria(collapsed);
|
|
15511
|
+
if (persist) {
|
|
15512
|
+
try { localStorage.setItem(STORE_KEY, collapsed ? '1' : '0'); } catch (e) { /* ignore */ }
|
|
15513
|
+
}
|
|
15514
|
+
}
|
|
15515
|
+
|
|
15516
|
+
function collapse() {
|
|
15517
|
+
apply(true, true);
|
|
15518
|
+
// Move focus to the rail's expand control so keyboard focus is never
|
|
15519
|
+
// orphaned on a now-hidden button.
|
|
15520
|
+
try { expandBtn.focus(); } catch (e) { /* ignore */ }
|
|
15521
|
+
}
|
|
15522
|
+
function expand() {
|
|
15523
|
+
apply(false, true);
|
|
15524
|
+
try { collapseBtn.focus(); } catch (e) { /* ignore */ }
|
|
15525
|
+
}
|
|
15526
|
+
|
|
15527
|
+
collapseBtn.addEventListener('click', collapse);
|
|
15528
|
+
expandBtn.addEventListener('click', expand);
|
|
15529
|
+
|
|
15530
|
+
// Restore remembered state (default expanded). Applied without persisting
|
|
15531
|
+
// and without stealing focus on load. On a narrow viewport the expanded
|
|
15532
|
+
// panel is a full overlay, so force the rail on load there (without
|
|
15533
|
+
// persisting -- the desktop preference is untouched); the user can still tap
|
|
15534
|
+
// expand to open the overlay and the header chevron to close it.
|
|
15535
|
+
var stored = null;
|
|
15536
|
+
try { stored = localStorage.getItem(STORE_KEY); } catch (e) { /* ignore */ }
|
|
15537
|
+
var startCollapsed = (window.innerWidth <= 768) ? true : (stored === '1');
|
|
15538
|
+
apply(startCollapsed, false);
|
|
15539
|
+
|
|
15540
|
+
// Glanceable live dot on the collapsed rail. Wired to the SAME shared API
|
|
15541
|
+
// client the session-control uses, so it reflects real connection state
|
|
15542
|
+
// rather than a static dot implying liveness it does not have.
|
|
15543
|
+
var dot = document.getElementById('status-rail-dot');
|
|
15544
|
+
if (dot && typeof LokiDashboard !== 'undefined' && LokiDashboard.getApiClient) {
|
|
15545
|
+
try {
|
|
15546
|
+
var api = LokiDashboard.getApiClient({ baseUrl: window.location.origin });
|
|
15547
|
+
function setConnected(connected) {
|
|
15548
|
+
dot.classList.toggle('connected', !!connected);
|
|
15549
|
+
dot.setAttribute('aria-label', connected ? 'Connected' : 'Disconnected');
|
|
15550
|
+
}
|
|
15551
|
+
api.addEventListener('api:connected', function () { setConnected(true); });
|
|
15552
|
+
api.addEventListener('api:disconnected', function () { setConnected(false); });
|
|
15553
|
+
api.addEventListener('api:status-update', function () { setConnected(true); });
|
|
15554
|
+
// Initial probe so the dot is honest before the first event arrives.
|
|
15555
|
+
if (typeof api.getStatus === 'function') {
|
|
15556
|
+
api.getStatus().then(function () { setConnected(true); })
|
|
15557
|
+
.catch(function () { setConnected(false); });
|
|
15558
|
+
}
|
|
15559
|
+
} catch (e) { /* leave the dot in its muted default */ }
|
|
15560
|
+
}
|
|
15561
|
+
})();
|
|
15562
|
+
|
|
15244
15563
|
// Offline detection
|
|
15245
15564
|
window.addEventListener('online', function() {
|
|
15246
15565
|
document.getElementById('offline-banner').classList.remove('show');
|
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.94.0
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -395,7 +395,7 @@ provider works inside the container. Provide auth with your Anthropic API key:
|
|
|
395
395
|
# Run Loki Mode in Docker (Claude provider, API-key auth)
|
|
396
396
|
docker run --rm -e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \
|
|
397
397
|
-v $(pwd):/workspace -w /workspace \
|
|
398
|
-
asklokesh/loki-mode:7.
|
|
398
|
+
asklokesh/loki-mode:7.93.0 start ./my-spec.md
|
|
399
399
|
```
|
|
400
400
|
|
|
401
401
|
##### docker compose + .env (no host install)
|