aidevops 3.29.17 → 3.29.19
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/VERSION +1 -1
- package/aidevops.sh +1 -1
- package/package.json +1 -1
- package/packages/gui-web/src/App.tsx +5 -8
- package/packages/gui-web/src/AppNavigation.tsx +20 -8
- package/packages/gui-web/src/app-model.ts +6 -6
- package/packages/gui-web/src/dashboard.ts +1 -1
- package/packages/gui-web/src/navigation-history.ts +49 -0
- package/packages/gui-web/src/styles.css +28 -15
- package/setup.sh +1 -1
package/README.md
CHANGED
|
@@ -58,7 +58,7 @@ The result: an AI operations platform that manages projects across every busines
|
|
|
58
58
|
[](https://github.com/marcusquinn)
|
|
59
59
|
|
|
60
60
|
<!-- Release & Version Info -->
|
|
61
|
-
[](https://github.com/marcusquinn/aidevops/releases)
|
|
62
62
|
[](https://www.npmjs.com/package/aidevops)
|
|
63
63
|
[](https://github.com/marcusquinn/homebrew-tap)
|
|
64
64
|
[](https://github.com/marcusquinn/aidevops)
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.29.
|
|
1
|
+
3.29.19
|
package/aidevops.sh
CHANGED
package/package.json
CHANGED
|
@@ -4,13 +4,9 @@ import { MachineRail, Sidebar } from "./AppNavigation";
|
|
|
4
4
|
import { Workspace } from "./AppWorkspace";
|
|
5
5
|
import type { ConversationMode, FontPreference, FontSizePreference, ShellMode, SurfaceId, ThemePreference } from "./app-model";
|
|
6
6
|
import { DEFAULT_ACCENT_HUE, DEFAULT_FONT, DEFAULT_FONT_SIZE, fileRootBySurface, findSurface, findSurfaceSectionLabel, fontFamilyForPreference, fontSizeForPreference, getSystemTheme, isFontPreference, isFontSizePreference } from "./app-model";
|
|
7
|
+
import { type NavigationHistory, nextHistoryIndex, useNavigationHistoryKeyboard } from "./navigation-history";
|
|
7
8
|
import { fetchStatus, mockedStatus } from "./status-client";
|
|
8
9
|
|
|
9
|
-
interface NavigationHistory {
|
|
10
|
-
entries: SurfaceId[];
|
|
11
|
-
index: number;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
10
|
interface WebKitBridgeWindow extends Window {
|
|
15
11
|
webkit?: {
|
|
16
12
|
messageHandlers?: {
|
|
@@ -37,7 +33,7 @@ export const appearanceStorageKeys = {
|
|
|
37
33
|
} as const;
|
|
38
34
|
|
|
39
35
|
const defaultSidebarWidth = 302;
|
|
40
|
-
const minSidebarWidth =
|
|
36
|
+
const minSidebarWidth = 300;
|
|
41
37
|
const maxSidebarWidth = 520;
|
|
42
38
|
export const loadingSkeletonPanelLabels = ["machine rail", "sidebar", "workspace", "status bar"] as const;
|
|
43
39
|
export const loadingBrandGlyph = ">_";
|
|
@@ -93,6 +89,7 @@ export function App(): ReactElement {
|
|
|
93
89
|
const canGoBack = navigation.index > 0;
|
|
94
90
|
const canGoForward = navigation.index < navigation.entries.length - 1;
|
|
95
91
|
const fileRoot = fileRootBySurface[activeSurface];
|
|
92
|
+
useNavigationHistoryKeyboard(setNavigation);
|
|
96
93
|
|
|
97
94
|
const setActiveSurface = (surface: SurfaceId) => {
|
|
98
95
|
setNavigation((current) => {
|
|
@@ -108,11 +105,11 @@ export function App(): ReactElement {
|
|
|
108
105
|
};
|
|
109
106
|
|
|
110
107
|
const goBack = () => {
|
|
111
|
-
setNavigation((current) => ({ ...current, index:
|
|
108
|
+
setNavigation((current) => ({ ...current, index: nextHistoryIndex(current, -1) }));
|
|
112
109
|
};
|
|
113
110
|
|
|
114
111
|
const goForward = () => {
|
|
115
|
-
setNavigation((current) => ({ ...current, index:
|
|
112
|
+
setNavigation((current) => ({ ...current, index: nextHistoryIndex(current, 1) }));
|
|
116
113
|
};
|
|
117
114
|
|
|
118
115
|
useEffect(() => {
|
|
@@ -145,7 +145,7 @@ export function Sidebar({ activeSurface, accentHue, conversationMode, fontPrefer
|
|
|
145
145
|
|
|
146
146
|
return (
|
|
147
147
|
<aside className="app-sidebar" aria-label={text.navigationLabel}>
|
|
148
|
-
<SidebarHeader setShellMode={setShellMode} shellMode={shellMode} />
|
|
148
|
+
<SidebarHeader setActiveSurface={setActiveSurface} setShellMode={setShellMode} shellMode={shellMode} />
|
|
149
149
|
<nav className="sidebar-content">
|
|
150
150
|
{shellMode === "devices" ? <>
|
|
151
151
|
<SidebarModeTabs mode={sidebarMode} setMode={(mode) => setSidebarMode(mode as SidebarMode)} />
|
|
@@ -357,17 +357,18 @@ function SidebarItem({ activeSurface, item, recordCount, setActiveSurface, showC
|
|
|
357
357
|
);
|
|
358
358
|
}
|
|
359
359
|
|
|
360
|
-
function SidebarHeader({ setShellMode, shellMode }: {
|
|
360
|
+
function SidebarHeader({ setActiveSurface, setShellMode, shellMode }: {
|
|
361
|
+
setActiveSurface: (surface: SurfaceId) => void;
|
|
361
362
|
setShellMode: (mode: ShellMode) => void;
|
|
362
363
|
shellMode: ShellMode;
|
|
363
364
|
}) {
|
|
364
365
|
return (
|
|
365
366
|
<header className="sidebar-header">
|
|
366
367
|
<div className="sidebar-titlebar">
|
|
367
|
-
<
|
|
368
|
+
<button className="brand-lockup" onClick={() => setActiveSurface(dashboardNavItem.id)} title="Return to dashboard" type="button">
|
|
368
369
|
<span className="terminal-mark" aria-hidden="true">›_</span>
|
|
369
370
|
<strong>{text.aidevops}</strong>
|
|
370
|
-
</
|
|
371
|
+
</button>
|
|
371
372
|
<IconSwitch
|
|
372
373
|
ariaLabel="Navigation scope"
|
|
373
374
|
options={[
|
|
@@ -501,14 +502,25 @@ function SidebarFooter({ accentHue, fontPreference, fontSizePreference, setAccen
|
|
|
501
502
|
id="font-size-slider"
|
|
502
503
|
max={fontSizeOptions.length - 1}
|
|
503
504
|
min="0"
|
|
504
|
-
onChange={(event) => setFontSizePreference(fontSizeOptions[Number.parseInt(event.currentTarget.value, 10)]?.value ?? "
|
|
505
|
+
onChange={(event) => setFontSizePreference(fontSizeOptions[Number.parseInt(event.currentTarget.value, 10)]?.value ?? "xs")}
|
|
505
506
|
step="1"
|
|
506
507
|
type="range"
|
|
507
508
|
value={fontSizeIndex}
|
|
508
509
|
/>
|
|
509
|
-
<
|
|
510
|
-
|
|
511
|
-
|
|
510
|
+
<fieldset className="range-labels">
|
|
511
|
+
<legend className="sr-only">Font size shortcuts</legend>
|
|
512
|
+
{fontSizeOptions.map((option) => (
|
|
513
|
+
<button
|
|
514
|
+
aria-pressed={option.value === fontSizePreference}
|
|
515
|
+
className={option.value === fontSizePreference ? "active" : ""}
|
|
516
|
+
key={option.value}
|
|
517
|
+
onClick={() => setFontSizePreference(option.value)}
|
|
518
|
+
type="button"
|
|
519
|
+
>
|
|
520
|
+
{option.label}
|
|
521
|
+
</button>
|
|
522
|
+
))}
|
|
523
|
+
</fieldset>
|
|
512
524
|
</div>
|
|
513
525
|
<div className="font-control">
|
|
514
526
|
<span id="appearance-font-selector-label">{text.font}</span>
|
|
@@ -303,15 +303,15 @@ export const text = {
|
|
|
303
303
|
} as const;
|
|
304
304
|
|
|
305
305
|
export const DEFAULT_ACCENT_HUE = 123;
|
|
306
|
-
export const DEFAULT_FONT: FontPreference = "
|
|
307
|
-
export const DEFAULT_FONT_SIZE: FontSizePreference = "
|
|
306
|
+
export const DEFAULT_FONT: FontPreference = "Inter";
|
|
307
|
+
export const DEFAULT_FONT_SIZE: FontSizePreference = "xs";
|
|
308
308
|
|
|
309
309
|
export const fontOptions: FontOption[] = [
|
|
310
310
|
{ value: "IBM Plex Mono", label: "IBM Plex Mono", fontFamily: '"IBM Plex Mono", Menlo, Monaco, Consolas, monospace' },
|
|
311
311
|
{ value: "IBM Plex Sans", label: "IBM Plex Sans", fontFamily: '"IBM Plex Sans", Inter, system-ui, sans-serif' },
|
|
312
312
|
{ value: "IBM Plex Serif", label: "IBM Plex Serif", fontFamily: '"IBM Plex Serif", Georgia, serif' },
|
|
313
|
-
{ value: "Inter", label: "Inter", fontFamily: 'Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif' },
|
|
314
|
-
{ value: "Menlo", label: "Menlo
|
|
313
|
+
{ value: "Inter", label: "Inter (default)", fontFamily: 'Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif' },
|
|
314
|
+
{ value: "Menlo", label: "Menlo", fontFamily: 'Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace' },
|
|
315
315
|
{ value: "Playpen Sans", label: "Playpen Sans", fontFamily: '"Playpen Sans", "Comic Sans MS", Inter, system-ui, sans-serif' },
|
|
316
316
|
{ value: "Poppins", label: "Poppins", fontFamily: 'Poppins, Inter, system-ui, sans-serif' },
|
|
317
317
|
{ value: "Source Sans", label: "Source Sans", fontFamily: '"Source Sans 3", "Source Sans Pro", "Source Sans", Inter, system-ui, sans-serif' },
|
|
@@ -543,11 +543,11 @@ export function getSystemTheme(): "light" | "dark" {
|
|
|
543
543
|
}
|
|
544
544
|
|
|
545
545
|
export function fontFamilyForPreference(font: FontPreference): string {
|
|
546
|
-
return fontOptions.find((option) => option.value === font)?.fontFamily ?? fontOptions.find((option) => option.value === DEFAULT_FONT)?.fontFamily ?? "
|
|
546
|
+
return fontOptions.find((option) => option.value === font)?.fontFamily ?? fontOptions.find((option) => option.value === DEFAULT_FONT)?.fontFamily ?? "Inter, system-ui, sans-serif";
|
|
547
547
|
}
|
|
548
548
|
|
|
549
549
|
export function fontSizeForPreference(size: FontSizePreference): string {
|
|
550
|
-
return fontSizeOptions.find((option) => option.value === size)?.cssSize ?? fontSizeOptions.find((option) => option.value === DEFAULT_FONT_SIZE)?.cssSize ?? "
|
|
550
|
+
return fontSizeOptions.find((option) => option.value === size)?.cssSize ?? fontSizeOptions.find((option) => option.value === DEFAULT_FONT_SIZE)?.cssSize ?? "14px";
|
|
551
551
|
}
|
|
552
552
|
|
|
553
553
|
export function isFontPreference(value: string | null): value is FontPreference {
|
|
@@ -55,7 +55,7 @@ export function renderDashboardHtml(status: GuiResponseEnvelope<GuiStatusData>):
|
|
|
55
55
|
`<h1>aidevops app interface</h1>`,
|
|
56
56
|
`<p>Made for creators.</p>`,
|
|
57
57
|
`<p>AI-assisted development workflows, code quality, and deployment automation.</p>`,
|
|
58
|
-
`<p>Theme follows system preferences with light and dark overrides. Sidebar modes: DevOps and Comms. Appearance controls can be hidden or shown, and include editable Hue, icon Reset, Show borders toggle, Show counts toggle, Font size choices xs, s, m, lg, xl, and Font options: IBM Plex Mono, IBM Plex Sans, IBM Plex Serif, Inter
|
|
58
|
+
`<p>Theme follows system preferences with light and dark overrides. Sidebar modes: DevOps and Comms. Appearance controls can be hidden or shown, and include editable Hue, icon Reset, Show borders toggle, Show counts toggle, Font size choices xs, s, m, lg, xl, and Font options: IBM Plex Mono, IBM Plex Sans, IBM Plex Serif, Inter (default), Menlo, Playpen Sans, Poppins, Source Sans, Source Serif, Tilt Neon, Ubuntu Mono. The workspace header includes a command palette, reserved signposts/help slot immediately left of notifications, notifications menu, AI Assistant panel, and profile menu with Settings, Theme, Language, Community, Admin, and Logout entries. Notifications reuse the OpenCode toast status cache and GUI readiness data. A desktop status bar shows local readiness, repo totals, secret reference count, provider accounts, and update state.</p>`,
|
|
59
59
|
`<p>Secret references stay read-only and redacted.</p>`,
|
|
60
60
|
`<p>Vault surfaces show padlock indicators. Encrypted by aidevops Vault; contents visible only when unlocked through app or authorised vault commands.</p>`,
|
|
61
61
|
`<p>${escapeHtml(status.data.update.message)}</p>`,
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { type Dispatch, type SetStateAction, useEffect } from "react";
|
|
2
|
+
import type { SurfaceId } from "./app-model";
|
|
3
|
+
|
|
4
|
+
export interface NavigationHistory {
|
|
5
|
+
entries: SurfaceId[];
|
|
6
|
+
index: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function nextHistoryIndex(current: NavigationHistory, direction: -1 | 1): number {
|
|
10
|
+
return Math.min(Math.max(0, current.entries.length - 1), Math.max(0, current.index + direction));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function useNavigationHistoryKeyboard(setNavigation: Dispatch<SetStateAction<NavigationHistory>>): void {
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
const navigateHistoryWithKeyboard = (event: globalThis.KeyboardEvent) => {
|
|
16
|
+
if (shouldIgnoreHistoryShortcut(event)) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const direction = historyShortcutDirection(event.key);
|
|
21
|
+
if (direction === null) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
event.preventDefault();
|
|
26
|
+
setNavigation((current) => ({ ...current, index: nextHistoryIndex(current, direction) }));
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
window.addEventListener("keydown", navigateHistoryWithKeyboard);
|
|
30
|
+
|
|
31
|
+
return () => window.removeEventListener("keydown", navigateHistoryWithKeyboard);
|
|
32
|
+
}, [setNavigation]);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function shouldIgnoreHistoryShortcut(event: globalThis.KeyboardEvent): boolean {
|
|
36
|
+
return !(event.metaKey || event.ctrlKey) || isEditableKeyboardTarget(event.target) || isEditableKeyboardTarget(document.activeElement);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function historyShortcutDirection(key: string): -1 | 1 | null {
|
|
40
|
+
return key === "[" ? -1 : key === "]" ? 1 : null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function isEditableKeyboardTarget(target: EventTarget | null): boolean {
|
|
44
|
+
if (typeof HTMLElement === "undefined" || !(target instanceof HTMLElement)) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return target.isContentEditable || target.closest("input, textarea, select, [contenteditable], [role='textbox']") !== null;
|
|
49
|
+
}
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
--border-hover: color-mix(in srgb, rgb(0 0 0 / 24%) 64%, rgb(255 255 255 / 48%));
|
|
11
11
|
--code-bg: hsl(var(--accent-hue) 55% 91%);
|
|
12
12
|
--desktop-titlebar-height: 0px;
|
|
13
|
-
--font-family-app:
|
|
14
|
-
--font-size-app:
|
|
13
|
+
--font-family-app: Inter, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
14
|
+
--font-size-app: 14px;
|
|
15
15
|
--glass-panel-shadow: inset 0 1px 0 rgb(255 255 255 / 58%), inset 0 -1px 0 rgb(0 0 0 / 3%), var(--shadow-soft);
|
|
16
16
|
--notification-error-bg: rgb(207 34 46 / 10%);
|
|
17
17
|
--notification-error-fg: #cf222e;
|
|
@@ -119,7 +119,7 @@ code {
|
|
|
119
119
|
.app-shell {
|
|
120
120
|
display: grid;
|
|
121
121
|
column-gap: 8px;
|
|
122
|
-
grid-template-columns: 72px var(--sidebar-width, 302px)
|
|
122
|
+
grid-template-columns: 72px var(--sidebar-width, 302px) 6px minmax(0, 1fr);
|
|
123
123
|
grid-template-rows: minmax(0, 1fr) auto;
|
|
124
124
|
height: 100vh;
|
|
125
125
|
padding: calc(var(--shell-gutter) + var(--desktop-titlebar-height)) var(--shell-gutter) var(--shell-gutter);
|
|
@@ -127,7 +127,7 @@ code {
|
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
.app-shell.machine-rail-collapsed {
|
|
130
|
-
grid-template-columns: var(--sidebar-width, 302px)
|
|
130
|
+
grid-template-columns: var(--sidebar-width, 302px) 6px minmax(0, 1fr);
|
|
131
131
|
}
|
|
132
132
|
|
|
133
133
|
.desktop-titlebar-tagline {
|
|
@@ -296,10 +296,19 @@ code {
|
|
|
296
296
|
}
|
|
297
297
|
|
|
298
298
|
.brand-lockup {
|
|
299
|
+
background: transparent;
|
|
300
|
+
border: 0;
|
|
301
|
+
color: var(--text-primary);
|
|
299
302
|
gap: 12px;
|
|
300
303
|
padding: 2px 4px;
|
|
301
304
|
}
|
|
302
305
|
|
|
306
|
+
.brand-lockup:hover,
|
|
307
|
+
.brand-lockup:focus-visible {
|
|
308
|
+
color: var(--accent);
|
|
309
|
+
outline: none;
|
|
310
|
+
}
|
|
311
|
+
|
|
303
312
|
.sidebar-titlebar {
|
|
304
313
|
gap: 10px;
|
|
305
314
|
justify-content: space-between;
|
|
@@ -819,28 +828,32 @@ code {
|
|
|
819
828
|
}
|
|
820
829
|
|
|
821
830
|
.range-labels {
|
|
831
|
+
border: 0;
|
|
822
832
|
color: var(--text-muted);
|
|
823
833
|
display: grid;
|
|
824
834
|
font-size: 0.7rem;
|
|
825
835
|
font-weight: 900;
|
|
826
836
|
grid-template-columns: repeat(5, 1fr);
|
|
837
|
+
margin: 0;
|
|
838
|
+
padding: 0;
|
|
827
839
|
text-transform: uppercase;
|
|
828
840
|
}
|
|
829
841
|
|
|
830
|
-
.range-labels
|
|
842
|
+
.range-labels button {
|
|
843
|
+
background: transparent;
|
|
844
|
+
border: 0;
|
|
845
|
+
border-radius: 8px;
|
|
846
|
+
color: inherit;
|
|
847
|
+
font: inherit;
|
|
848
|
+
padding: 3px 0;
|
|
831
849
|
text-align: center;
|
|
832
850
|
}
|
|
833
851
|
|
|
834
|
-
.range-labels
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
.range-labels span:last-child {
|
|
839
|
-
text-align: right;
|
|
840
|
-
}
|
|
841
|
-
|
|
842
|
-
.range-labels .active {
|
|
852
|
+
.range-labels button:hover,
|
|
853
|
+
.range-labels button:focus-visible,
|
|
854
|
+
.range-labels button.active {
|
|
843
855
|
color: var(--accent);
|
|
856
|
+
outline: none;
|
|
844
857
|
}
|
|
845
858
|
|
|
846
859
|
.font-control select {
|
|
@@ -2206,7 +2219,7 @@ code {
|
|
|
2206
2219
|
align-items: center;
|
|
2207
2220
|
color: var(--text-secondary);
|
|
2208
2221
|
display: inline-flex;
|
|
2209
|
-
font-size:
|
|
2222
|
+
font-size: 1em;
|
|
2210
2223
|
font-weight: 800;
|
|
2211
2224
|
gap: 4px;
|
|
2212
2225
|
max-width: 100%;
|
package/setup.sh
CHANGED
|
@@ -12,7 +12,7 @@ shopt -s inherit_errexit 2>/dev/null || true
|
|
|
12
12
|
# AI Assistant Server Access Framework Setup Script
|
|
13
13
|
# Helps developers set up the framework for their infrastructure
|
|
14
14
|
#
|
|
15
|
-
# Version: 3.29.
|
|
15
|
+
# Version: 3.29.19
|
|
16
16
|
#
|
|
17
17
|
# Quick Install:
|
|
18
18
|
# npm install -g aidevops && aidevops update (recommended)
|