aidevops 3.29.12 → 3.29.13
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/CommsConversationSurface.tsx +49 -12
- package/packages/gui-web/src/InventorySurfaces.tsx +13 -9
- package/packages/gui-web/src/app-model.ts +1 -1
- package/packages/gui-web/src/styles.css +72 -20
- 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.13
|
package/aidevops.sh
CHANGED
package/package.json
CHANGED
|
@@ -3,12 +3,29 @@ import { sortConversationMessageParts, sortConversationMessages, type GuiConvers
|
|
|
3
3
|
import { text } from "./app-model";
|
|
4
4
|
import { conversationThreads } from "./conversation-fixtures";
|
|
5
5
|
|
|
6
|
-
export function CommsConversationSurface({ mode }: { mode: "channels" | "directMessages" | "people" }) {
|
|
7
|
-
const
|
|
8
|
-
const
|
|
6
|
+
export function CommsConversationSurface({ mode, threads = conversationThreads }: { mode: "channels" | "directMessages" | "people"; threads?: GuiConversationThread[] }) {
|
|
7
|
+
const availableThreads = threads ?? [];
|
|
8
|
+
const conversations = mode === "directMessages" ? availableThreads.filter((thread) => thread.conversation.type === "dm" || thread.conversation.type === "group_dm") : availableThreads.filter((thread) => thread.conversation.type === "channel");
|
|
9
|
+
const selectedThread = conversations[0] ?? availableThreads[0];
|
|
9
10
|
const partsByMessage = new Map<string, GuiConversationMessagePart[]>();
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
if (!selectedThread) {
|
|
13
|
+
return (
|
|
14
|
+
<section className="chat-surface comms-surface" aria-label={mode === "directMessages" ? text.directMessages : text.channels} data-tour="comms-conversations">
|
|
15
|
+
<aside className="chat-thread-panel conversation-list-panel" aria-label="Conversation list">
|
|
16
|
+
<header className="chat-thread-header">
|
|
17
|
+
<div>
|
|
18
|
+
<p className="eyebrow">Unified conversation model</p>
|
|
19
|
+
<h2>{mode === "directMessages" ? <FiAtSign aria-hidden="true" /> : <FiHash aria-hidden="true" />} {mode === "directMessages" ? text.directMessages : text.channels}</h2>
|
|
20
|
+
</div>
|
|
21
|
+
</header>
|
|
22
|
+
<div className="notice compact-notice">No conversations yet</div>
|
|
23
|
+
</aside>
|
|
24
|
+
</section>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
for (const part of sortConversationMessageParts(conversationParts(selectedThread))) {
|
|
12
29
|
partsByMessage.set(part.message_id, [...(partsByMessage.get(part.message_id) ?? []), part]);
|
|
13
30
|
}
|
|
14
31
|
|
|
@@ -37,10 +54,10 @@ export function CommsConversationSurface({ mode }: { mode: "channels" | "directM
|
|
|
37
54
|
<span className="count-pill">{participantSummary(selectedThread)}</span>
|
|
38
55
|
</header>
|
|
39
56
|
<div className="participant-strip">
|
|
40
|
-
{selectedThread.
|
|
57
|
+
{conversationParticipants(selectedThread).map((participant) => <span key={participant.id}>{participant.display_name}<small>{participant.kind}</small></span>)}
|
|
41
58
|
</div>
|
|
42
59
|
<div className="chat-message-list" data-tour="comms-message-timeline">
|
|
43
|
-
{sortConversationMessages(selectedThread
|
|
60
|
+
{sortConversationMessages(conversationMessages(selectedThread)).map((message) => <ConversationMessageRow key={message.id} message={message} parts={partsByMessage.get(message.id) ?? []} thread={selectedThread} />)}
|
|
44
61
|
</div>
|
|
45
62
|
<form className="chat-composer" aria-label="Conversation composer">
|
|
46
63
|
<textarea disabled placeholder={text.chatInputPlaceholder} />
|
|
@@ -52,7 +69,7 @@ export function CommsConversationSurface({ mode }: { mode: "channels" | "directM
|
|
|
52
69
|
}
|
|
53
70
|
|
|
54
71
|
function ConversationListItem({ thread }: { thread: GuiConversationThread }) {
|
|
55
|
-
const latestMessage = sortConversationMessages(thread
|
|
72
|
+
const latestMessage = sortConversationMessages(conversationMessages(thread)).at(-1);
|
|
56
73
|
const unread = unreadCount(thread);
|
|
57
74
|
|
|
58
75
|
return (
|
|
@@ -67,8 +84,8 @@ function ConversationListItem({ thread }: { thread: GuiConversationThread }) {
|
|
|
67
84
|
}
|
|
68
85
|
|
|
69
86
|
function ConversationMessageRow({ message, parts, thread }: { message: GuiConversationMessage; parts: GuiConversationMessagePart[]; thread: GuiConversationThread }) {
|
|
70
|
-
const sender = thread.
|
|
71
|
-
const reactions = thread.
|
|
87
|
+
const sender = conversationParticipants(thread).find((participant) => participant.id === message.sender_participant_id);
|
|
88
|
+
const reactions = conversationReactions(thread).filter((reaction) => reaction.message_id === message.id);
|
|
72
89
|
const speaker = message.sender_kind === "human" ? "user" : "assistant";
|
|
73
90
|
|
|
74
91
|
return (
|
|
@@ -82,12 +99,32 @@ function ConversationMessageRow({ message, parts, thread }: { message: GuiConver
|
|
|
82
99
|
}
|
|
83
100
|
|
|
84
101
|
function participantSummary(thread: GuiConversationThread): string {
|
|
85
|
-
const active = thread.
|
|
102
|
+
const active = conversationParticipants(thread).filter((participant) => participant.membership_state === "active").length;
|
|
86
103
|
return `${active} members`;
|
|
87
104
|
}
|
|
88
105
|
|
|
89
106
|
function unreadCount(thread: GuiConversationThread): number {
|
|
90
|
-
const lastSequence = Math.max(0, ...thread.
|
|
91
|
-
const localRead = thread
|
|
107
|
+
const lastSequence = Math.max(0, ...conversationMessages(thread).map((message) => message.sequence));
|
|
108
|
+
const localRead = conversationReadStates(thread)[0]?.last_read_sequence ?? 0;
|
|
92
109
|
return Math.max(0, lastSequence - localRead);
|
|
93
110
|
}
|
|
111
|
+
|
|
112
|
+
function conversationMessages(thread: GuiConversationThread): GuiConversationMessage[] {
|
|
113
|
+
return thread.messages ?? [];
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function conversationParts(thread: GuiConversationThread): GuiConversationMessagePart[] {
|
|
117
|
+
return thread.parts ?? [];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function conversationParticipants(thread: GuiConversationThread): GuiConversationThread["participants"] {
|
|
121
|
+
return thread.participants ?? [];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function conversationReactions(thread: GuiConversationThread): GuiConversationThread["reactions"] {
|
|
125
|
+
return thread.reactions ?? [];
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function conversationReadStates(thread: GuiConversationThread): GuiConversationThread["read_states"] {
|
|
129
|
+
return thread.read_states ?? [];
|
|
130
|
+
}
|
|
@@ -29,6 +29,8 @@ export function AppsSurface({ status }: { status: GuiStatusData }): ReactElement
|
|
|
29
29
|
const managedApps = sortedManagedApps(status.managed_apps).map((app) => applyManagedPolicyToggles(app, policyToggles[app.id]));
|
|
30
30
|
const visibleManagedApps = managedApps.filter((app) => managedCategoryForApp(app) === managedCategory);
|
|
31
31
|
const visibleRecommendedApps = recommendedApps.filter((app) => recommendedAppMatchesFilters(app, recommendedPlatform, recommendedOs));
|
|
32
|
+
const selectRecommendedPlatform = (value: RecommendedPlatformFilterId) => setRecommendedPlatform((current) => nextRecommendedFilterValue(current, value, "all"));
|
|
33
|
+
const selectRecommendedOs = (value: RecommendedOsId) => setRecommendedOs((current) => nextRecommendedFilterValue(current, value, "all"));
|
|
32
34
|
|
|
33
35
|
useEffect(() => {
|
|
34
36
|
setExpandedAppId(visibleManagedApps[0]?.id ?? null);
|
|
@@ -85,7 +87,7 @@ export function AppsSurface({ status }: { status: GuiStatusData }): ReactElement
|
|
|
85
87
|
))}
|
|
86
88
|
</div>
|
|
87
89
|
<p className="empty-state compact-notice">Install/update actions run as allowlisted background jobs and stream inside each app panel. xterm.js with a node-pty bridge is the right next step for full TUI apps such as OpenCode; this view starts with non-interactive command logs.</p>
|
|
88
|
-
</> : <RecommendedAppsSurface apps={visibleRecommendedApps} os={recommendedOs} platform={recommendedPlatform} setOs={
|
|
90
|
+
</> : <RecommendedAppsSurface apps={visibleRecommendedApps} os={recommendedOs} platform={recommendedPlatform} setOs={selectRecommendedOs} setPlatform={selectRecommendedPlatform} />}
|
|
89
91
|
</section>
|
|
90
92
|
);
|
|
91
93
|
}
|
|
@@ -120,11 +122,9 @@ function ManagedAppPanel({ app, expanded, job, onJob, onPolicyToggle, onToggle,
|
|
|
120
122
|
<div className="managed-app-details">
|
|
121
123
|
<ToggleSwitch checked={app.aidevops_install} disabled={lockedPolicy} label="setup installs" onChange={(value) => onPolicyToggle("setup", value)} />
|
|
122
124
|
<ToggleSwitch checked={app.aidevops_update} disabled={lockedPolicy} label="update maintains" onChange={(value) => onPolicyToggle("update", value)} />
|
|
123
|
-
<AppMeta label="Installed" value={app.installed_version} />
|
|
124
|
-
<AppMeta label="Latest" value={app.latest_version} />
|
|
125
|
-
<AppMeta label={text.path} value={app.install_path_ref} />
|
|
126
125
|
{job ? <AppLogLink job={job} /> : null}
|
|
127
126
|
</div>
|
|
127
|
+
<AppMeta className="managed-app-path" label={text.path} value={app.install_path_ref} />
|
|
128
128
|
{job ? <AppActionTerminal job={job} /> : null}
|
|
129
129
|
{policyJobs.map((policyJob) => <AppActionTerminal job={policyJob} key={policyJob.id} />)}
|
|
130
130
|
{job === null && policyJobs.length === 0 ? <p className="empty-state compact-notice">No recent command output for this app. Run an action or change a policy toggle to open this app's terminal log.</p> : null}
|
|
@@ -146,11 +146,11 @@ function OriginLink({ href, label }: { href: string; label: string }): ReactElem
|
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
function ToggleSwitch({ checked, disabled = false, label, onChange }: { checked: boolean; disabled?: boolean; label: string; onChange: (checked: boolean) => void }): ReactElement {
|
|
149
|
-
return <button aria-pressed={checked} className={checked ? "managed-toggle checked" : "managed-toggle"} data-tooltip={disabled ? "Essential aidevops component; policy is locked on" : undefined} disabled={disabled} onClick={() => onChange(!checked)} title={disabled ? "Essential aidevops component; policy is locked on" : undefined} type="button"><span aria-hidden="true" className={checked ? "switch-track checked" : "switch-track"}><span /></span
|
|
149
|
+
return <button aria-pressed={checked} className={checked ? "managed-toggle checked" : "managed-toggle"} data-tooltip={disabled ? "Essential aidevops component; policy is locked on" : undefined} disabled={disabled} onClick={() => onChange(!checked)} title={disabled ? "Essential aidevops component; policy is locked on" : undefined} type="button"><span className="managed-toggle-label">{label}</span><span aria-hidden="true" className={checked ? "switch-track checked" : "switch-track"}><span /></span></button>;
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
-
function AppMeta({ label, value }: { label: string; value: string }): ReactElement {
|
|
153
|
-
return <span className="app-meta"><small>{label}</small><strong>{value}</strong></span>;
|
|
152
|
+
function AppMeta({ className = "", label, value }: { className?: string; label: string; value: string }): ReactElement {
|
|
153
|
+
return <span className={className.length > 0 ? `app-meta ${className}` : "app-meta"}><small>{label}</small><strong>{value}</strong></span>;
|
|
154
154
|
}
|
|
155
155
|
|
|
156
156
|
function AppLogLink({ job }: { job: GuiAppActionJobSummary }): ReactElement {
|
|
@@ -291,7 +291,7 @@ interface RecommendedApp {
|
|
|
291
291
|
}
|
|
292
292
|
|
|
293
293
|
const appCollectionTabs: TabOption<AppCollectionId>[] = [
|
|
294
|
-
{ id: "aidevops", label: "
|
|
294
|
+
{ id: "aidevops", label: "AIDevOps" },
|
|
295
295
|
{ id: "recommended", label: "Recommended" },
|
|
296
296
|
];
|
|
297
297
|
|
|
@@ -379,8 +379,8 @@ function TabNav<T extends string>({ label, onChange, tabs, value }: { label: str
|
|
|
379
379
|
function RecommendedAppsSurface({ apps, os, platform, setOs, setPlatform }: { apps: RecommendedApp[]; os: RecommendedOsId; platform: RecommendedPlatformFilterId; setOs: (os: RecommendedOsId) => void; setPlatform: (platform: RecommendedPlatformFilterId) => void }): ReactElement {
|
|
380
380
|
return <>
|
|
381
381
|
<div className="recommended-filter-tabs">
|
|
382
|
-
<TabNav label="Recommended app platform filters" tabs={recommendedPlatformTabs} value={platform} onChange={setPlatform} />
|
|
383
382
|
<TabNav label="Recommended app operating system filters" tabs={recommendedOsTabs} value={os} onChange={setOs} />
|
|
383
|
+
<TabNav label="Recommended app platform filters" tabs={recommendedPlatformTabs} value={platform} onChange={setPlatform} />
|
|
384
384
|
</div>
|
|
385
385
|
<div className="recommended-app-grid">
|
|
386
386
|
{apps.map((app) => <RecommendedAppCard app={app} key={app.name} setOs={setOs} setPlatform={setPlatform} />)}
|
|
@@ -459,6 +459,10 @@ function recommendedAppMatchesFilters(app: RecommendedApp, platform: Recommended
|
|
|
459
459
|
return platformMatches && osMatches;
|
|
460
460
|
}
|
|
461
461
|
|
|
462
|
+
export function nextRecommendedFilterValue<T extends string>(current: T, next: T, defaultValue: T): T {
|
|
463
|
+
return current === next && next !== defaultValue ? defaultValue : next;
|
|
464
|
+
}
|
|
465
|
+
|
|
462
466
|
function applyManagedPolicyToggles(app: GuiManagedAppSummary, policy: Partial<Record<ManagedPolicyId, boolean>> | undefined): GuiManagedAppSummary {
|
|
463
467
|
if (policy === undefined) {
|
|
464
468
|
return app;
|
|
@@ -147,7 +147,7 @@ export const text = {
|
|
|
147
147
|
aidevops: "aidevops",
|
|
148
148
|
appShell: "App shell",
|
|
149
149
|
apps: "Apps",
|
|
150
|
-
appsIntro: "
|
|
150
|
+
appsIntro: "The app toolkit we use and recommend to enable all the things we can do with AI, development, and operations to create and share our work. Opinionated preferences based on open-source-first, lowest-costs, highest-quality UI & UX, teamwork, data security, privacy, and AI-usage capabilities.",
|
|
151
151
|
appStatusPending: "adapter pending",
|
|
152
152
|
brands: "Brands",
|
|
153
153
|
brandsIntro: "Draft brand inventory for names and website references.",
|
|
@@ -943,9 +943,8 @@ code {
|
|
|
943
943
|
.header-actions > .header-action-menu {
|
|
944
944
|
align-items: center;
|
|
945
945
|
display: inline-flex;
|
|
946
|
-
flex: 0 0
|
|
946
|
+
flex: 0 0 auto;
|
|
947
947
|
justify-content: center;
|
|
948
|
-
width: 38px;
|
|
949
948
|
}
|
|
950
949
|
|
|
951
950
|
.workspace-search {
|
|
@@ -1001,6 +1000,7 @@ code {
|
|
|
1001
1000
|
}
|
|
1002
1001
|
|
|
1003
1002
|
.header-action-menu {
|
|
1003
|
+
gap: 10px;
|
|
1004
1004
|
position: relative;
|
|
1005
1005
|
}
|
|
1006
1006
|
|
|
@@ -1784,15 +1784,23 @@ code {
|
|
|
1784
1784
|
}
|
|
1785
1785
|
|
|
1786
1786
|
.section-heading {
|
|
1787
|
-
margin-bottom:
|
|
1787
|
+
margin-bottom: 16px;
|
|
1788
1788
|
max-width: 860px;
|
|
1789
1789
|
}
|
|
1790
1790
|
|
|
1791
|
+
.section-heading .eyebrow {
|
|
1792
|
+
margin: 0 0 9px;
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1791
1795
|
.section-heading h2 {
|
|
1792
1796
|
font-size: 1.7rem;
|
|
1793
1797
|
letter-spacing: -0.05em;
|
|
1794
1798
|
line-height: 1.04;
|
|
1795
|
-
margin:
|
|
1799
|
+
margin: 0 0 16px;
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1802
|
+
.section-heading p {
|
|
1803
|
+
margin: 0;
|
|
1796
1804
|
}
|
|
1797
1805
|
|
|
1798
1806
|
.section-heading p,
|
|
@@ -2003,13 +2011,25 @@ code {
|
|
|
2003
2011
|
}
|
|
2004
2012
|
|
|
2005
2013
|
.apps-surface {
|
|
2006
|
-
display: grid;
|
|
2007
2014
|
align-content: start;
|
|
2008
|
-
|
|
2015
|
+
display: grid;
|
|
2016
|
+
gap: 0;
|
|
2009
2017
|
}
|
|
2010
2018
|
|
|
2011
2019
|
.apps-surface .section-heading {
|
|
2012
|
-
margin-bottom:
|
|
2020
|
+
margin-bottom: 18px;
|
|
2021
|
+
}
|
|
2022
|
+
|
|
2023
|
+
.apps-surface > .app-subnav {
|
|
2024
|
+
margin-bottom: 18px;
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
.apps-surface > .app-subnav + .app-subnav {
|
|
2028
|
+
margin-bottom: 16px;
|
|
2029
|
+
}
|
|
2030
|
+
|
|
2031
|
+
.apps-surface .compact-notice {
|
|
2032
|
+
margin-bottom: 0;
|
|
2013
2033
|
}
|
|
2014
2034
|
|
|
2015
2035
|
.data-table,
|
|
@@ -2021,8 +2041,8 @@ code {
|
|
|
2021
2041
|
}
|
|
2022
2042
|
|
|
2023
2043
|
.managed-app-list {
|
|
2024
|
-
gap:
|
|
2025
|
-
margin-bottom:
|
|
2044
|
+
gap: 16px;
|
|
2045
|
+
margin-bottom: 16px;
|
|
2026
2046
|
overflow: visible;
|
|
2027
2047
|
}
|
|
2028
2048
|
|
|
@@ -2033,7 +2053,7 @@ code {
|
|
|
2033
2053
|
border: 1px solid var(--border);
|
|
2034
2054
|
border-radius: 18px;
|
|
2035
2055
|
box-shadow: inset 0 1px 0 rgb(255 255 255 / 7%);
|
|
2036
|
-
overflow:
|
|
2056
|
+
overflow: visible;
|
|
2037
2057
|
transition: background 140ms ease, border-color 140ms ease;
|
|
2038
2058
|
}
|
|
2039
2059
|
|
|
@@ -2071,14 +2091,23 @@ code {
|
|
|
2071
2091
|
.managed-app-title-block,
|
|
2072
2092
|
.app-meta {
|
|
2073
2093
|
display: grid;
|
|
2074
|
-
gap: 7px;
|
|
2075
2094
|
min-width: 0;
|
|
2076
2095
|
}
|
|
2077
2096
|
|
|
2097
|
+
.managed-app-title-block {
|
|
2098
|
+
gap: 0;
|
|
2099
|
+
}
|
|
2100
|
+
|
|
2101
|
+
.managed-app-title-block .eyebrow {
|
|
2102
|
+
line-height: 1;
|
|
2103
|
+
margin: 0 0 8px;
|
|
2104
|
+
}
|
|
2105
|
+
|
|
2078
2106
|
.managed-app-title-block strong {
|
|
2079
2107
|
font-size: clamp(1.12rem, 2vw, 1.4rem);
|
|
2080
2108
|
letter-spacing: -0.04em;
|
|
2081
2109
|
line-height: 1.15;
|
|
2110
|
+
margin-bottom: 16px;
|
|
2082
2111
|
}
|
|
2083
2112
|
|
|
2084
2113
|
.managed-app-title-block > span:last-child {
|
|
@@ -2097,14 +2126,16 @@ code {
|
|
|
2097
2126
|
|
|
2098
2127
|
.managed-summary-chip {
|
|
2099
2128
|
align-items: center;
|
|
2129
|
+
align-content: center;
|
|
2100
2130
|
background: color-mix(in srgb, var(--surface-elevated) 92%, transparent);
|
|
2101
2131
|
border: 1px solid var(--border);
|
|
2102
2132
|
border-radius: 999px;
|
|
2103
2133
|
display: inline-grid;
|
|
2104
2134
|
gap: 1px;
|
|
2105
2135
|
justify-items: center;
|
|
2136
|
+
min-height: 58px;
|
|
2106
2137
|
min-width: 118px;
|
|
2107
|
-
padding: 7px
|
|
2138
|
+
padding: 7px 12px;
|
|
2108
2139
|
text-align: center;
|
|
2109
2140
|
}
|
|
2110
2141
|
|
|
@@ -2120,6 +2151,7 @@ code {
|
|
|
2120
2151
|
color: var(--text-primary);
|
|
2121
2152
|
font-size: 0.84rem;
|
|
2122
2153
|
font-weight: 800;
|
|
2154
|
+
line-height: 1.15;
|
|
2123
2155
|
max-width: 18ch;
|
|
2124
2156
|
overflow: hidden;
|
|
2125
2157
|
text-overflow: ellipsis;
|
|
@@ -2139,7 +2171,7 @@ code {
|
|
|
2139
2171
|
.managed-app-body {
|
|
2140
2172
|
border-top: 1px solid var(--border);
|
|
2141
2173
|
display: grid;
|
|
2142
|
-
gap:
|
|
2174
|
+
gap: 16px;
|
|
2143
2175
|
padding: 0 16px 16px;
|
|
2144
2176
|
position: relative;
|
|
2145
2177
|
}
|
|
@@ -2147,9 +2179,9 @@ code {
|
|
|
2147
2179
|
.managed-app-toolbar {
|
|
2148
2180
|
align-items: start;
|
|
2149
2181
|
display: grid;
|
|
2150
|
-
gap:
|
|
2182
|
+
gap: 16px;
|
|
2151
2183
|
grid-template-columns: minmax(0, 1fr) auto;
|
|
2152
|
-
padding-top:
|
|
2184
|
+
padding-top: 16px;
|
|
2153
2185
|
}
|
|
2154
2186
|
|
|
2155
2187
|
.managed-app-links,
|
|
@@ -2195,11 +2227,16 @@ code {
|
|
|
2195
2227
|
grid-template-columns: repeat(auto-fit, minmax(168px, 1fr));
|
|
2196
2228
|
}
|
|
2197
2229
|
|
|
2230
|
+
.managed-app-path {
|
|
2231
|
+
min-height: auto;
|
|
2232
|
+
}
|
|
2233
|
+
|
|
2198
2234
|
.managed-toggle,
|
|
2199
2235
|
.app-meta {
|
|
2200
2236
|
background: var(--surface-elevated);
|
|
2201
2237
|
border: 1px solid var(--border);
|
|
2202
2238
|
border-radius: 12px;
|
|
2239
|
+
gap: 7px;
|
|
2203
2240
|
min-width: 0;
|
|
2204
2241
|
min-height: 64px;
|
|
2205
2242
|
padding: 10px 12px;
|
|
@@ -2211,10 +2248,15 @@ code {
|
|
|
2211
2248
|
display: flex;
|
|
2212
2249
|
font-size: 0.78rem;
|
|
2213
2250
|
font-weight: 800;
|
|
2214
|
-
gap:
|
|
2251
|
+
gap: 12px;
|
|
2252
|
+
justify-content: space-between;
|
|
2215
2253
|
text-transform: uppercase;
|
|
2216
2254
|
}
|
|
2217
2255
|
|
|
2256
|
+
.managed-toggle-label {
|
|
2257
|
+
min-width: 0;
|
|
2258
|
+
}
|
|
2259
|
+
|
|
2218
2260
|
button.managed-toggle {
|
|
2219
2261
|
cursor: pointer;
|
|
2220
2262
|
text-align: left;
|
|
@@ -2236,6 +2278,7 @@ button.managed-toggle:focus-visible {
|
|
|
2236
2278
|
border: 1px solid color-mix(in srgb, #ef4444 44%, var(--border));
|
|
2237
2279
|
border-radius: 999px;
|
|
2238
2280
|
display: inline-flex;
|
|
2281
|
+
flex: 0 0 auto;
|
|
2239
2282
|
padding: 2px;
|
|
2240
2283
|
width: 34px;
|
|
2241
2284
|
}
|
|
@@ -2293,19 +2336,27 @@ button.managed-toggle:focus-visible {
|
|
|
2293
2336
|
color: var(--accent);
|
|
2294
2337
|
display: inline-flex;
|
|
2295
2338
|
gap: 7px;
|
|
2296
|
-
min-height: 42px;
|
|
2297
2339
|
justify-content: center;
|
|
2340
|
+
line-height: 1;
|
|
2341
|
+
min-height: 42px;
|
|
2298
2342
|
padding: 0 12px;
|
|
2299
2343
|
position: relative;
|
|
2300
2344
|
transition: background 140ms ease, border-color 140ms ease, color 140ms ease, transform 140ms ease;
|
|
2301
2345
|
}
|
|
2302
2346
|
|
|
2303
2347
|
.app-action-button span {
|
|
2348
|
+
align-items: center;
|
|
2349
|
+
display: inline-flex;
|
|
2304
2350
|
font-size: 0.7rem;
|
|
2305
2351
|
font-weight: 900;
|
|
2352
|
+
line-height: 1;
|
|
2306
2353
|
text-transform: uppercase;
|
|
2307
2354
|
}
|
|
2308
2355
|
|
|
2356
|
+
.app-action-button svg {
|
|
2357
|
+
flex: 0 0 auto;
|
|
2358
|
+
}
|
|
2359
|
+
|
|
2309
2360
|
.app-action-button:hover,
|
|
2310
2361
|
.app-action-button:focus-visible {
|
|
2311
2362
|
background: var(--accent);
|
|
@@ -2421,7 +2472,7 @@ button.managed-toggle:focus-visible {
|
|
|
2421
2472
|
content: attr(data-tooltip);
|
|
2422
2473
|
font-size: 0.72rem;
|
|
2423
2474
|
font-weight: 700;
|
|
2424
|
-
left:
|
|
2475
|
+
left: 50%;
|
|
2425
2476
|
line-height: 1.35;
|
|
2426
2477
|
max-width: min(320px, 72vw);
|
|
2427
2478
|
opacity: 0;
|
|
@@ -2432,7 +2483,7 @@ button.managed-toggle:focus-visible {
|
|
|
2432
2483
|
transform: translate(-50%, 4px);
|
|
2433
2484
|
transition: opacity 140ms ease, transform 140ms ease;
|
|
2434
2485
|
width: max-content;
|
|
2435
|
-
z-index:
|
|
2486
|
+
z-index: 1000;
|
|
2436
2487
|
}
|
|
2437
2488
|
|
|
2438
2489
|
[data-tooltip]:hover::after,
|
|
@@ -2526,7 +2577,8 @@ button.managed-toggle:focus-visible {
|
|
|
2526
2577
|
.recommended-filter-tabs {
|
|
2527
2578
|
display: flex;
|
|
2528
2579
|
flex-wrap: wrap;
|
|
2529
|
-
gap:
|
|
2580
|
+
gap: 16px;
|
|
2581
|
+
margin-bottom: 16px;
|
|
2530
2582
|
}
|
|
2531
2583
|
|
|
2532
2584
|
.recommended-app-grid {
|
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.13
|
|
16
16
|
#
|
|
17
17
|
# Quick Install:
|
|
18
18
|
# npm install -g aidevops && aidevops update (recommended)
|