@polderlabs/bizar 4.4.12 → 4.5.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/bizar-dash/CHANGELOG.md +37 -276
- package/bizar-dash/dist/assets/main-CDFKHzBg.css +1 -0
- package/bizar-dash/dist/assets/main-NYFpS2wY.js +312 -0
- package/bizar-dash/dist/assets/main-NYFpS2wY.js.map +1 -0
- package/bizar-dash/dist/assets/{mobile-DSb-t42Y.js → mobile--0FBIKX3.js} +2 -2
- package/bizar-dash/dist/assets/{mobile-DSb-t42Y.js.map → mobile--0FBIKX3.js.map} +1 -1
- package/bizar-dash/dist/assets/mobile-OgRp8VIb.js +352 -0
- package/bizar-dash/dist/assets/mobile-OgRp8VIb.js.map +1 -0
- package/bizar-dash/dist/index.html +3 -3
- package/bizar-dash/dist/mobile.html +2 -2
- package/bizar-dash/skills/agent-baseline/SKILL.md +80 -0
- package/bizar-dash/skills/bizar/SKILL.md +96 -0
- package/bizar-dash/skills/chat/SKILL.md +74 -0
- package/bizar-dash/skills/lightrag/SKILL.md +75 -0
- package/bizar-dash/skills/minimax/SKILL.md +80 -0
- package/bizar-dash/skills/obsidian/SKILL.md +55 -0
- package/bizar-dash/skills/providers/SKILL.md +75 -0
- package/bizar-dash/skills/sdk/SKILL.md +138 -0
- package/bizar-dash/skills/self-improvement/SKILL.md +53 -0
- package/bizar-dash/skills/skills-cli/SKILL.md +94 -0
- package/bizar-dash/skills/usage/SKILL.md +62 -0
- package/bizar-dash/src/server/api.mjs +12 -0
- package/bizar-dash/src/server/memory-lightrag.mjs +5 -2
- package/bizar-dash/src/server/memory-store.mjs +38 -0
- package/bizar-dash/src/server/minimax-usage-store.mjs +372 -0
- package/bizar-dash/src/server/minimax.mjs +427 -110
- package/bizar-dash/src/server/providers-store.mjs +966 -6
- package/bizar-dash/src/server/routes/config.mjs +52 -1
- package/bizar-dash/src/server/routes/env-vars.mjs +165 -0
- package/bizar-dash/src/server/routes/lightrag.mjs +154 -0
- package/bizar-dash/src/server/routes/memory.mjs +241 -1
- package/bizar-dash/src/server/routes/minimax.mjs +50 -57
- package/bizar-dash/src/server/routes/opencode-session-detail.mjs +14 -29
- package/bizar-dash/src/server/routes/opencode-sessions.mjs +205 -3
- package/bizar-dash/src/server/routes/providers.mjs +266 -5
- package/bizar-dash/src/server/routes/skills.mjs +32 -43
- package/bizar-dash/src/server/routes/update.mjs +340 -0
- package/bizar-dash/src/server/routes/usage.mjs +136 -0
- package/bizar-dash/src/server/serve-info.mjs +135 -4
- package/bizar-dash/src/server/server.mjs +4 -0
- package/bizar-dash/src/server/skills-store.mjs +152 -262
- package/bizar-dash/src/web/App.tsx +118 -29
- package/bizar-dash/src/web/components/EnvVarManager.tsx +247 -0
- package/bizar-dash/src/web/components/SettingsSearch.tsx +213 -0
- package/bizar-dash/src/web/components/Topbar.tsx +0 -1
- package/bizar-dash/src/web/components/UsageChart.tsx +250 -0
- package/bizar-dash/src/web/components/UsageTable.tsx +90 -0
- package/bizar-dash/src/web/components/chat/ChatComposer.tsx +21 -25
- package/bizar-dash/src/web/components/chat/ChatInfoPanel.tsx +199 -37
- package/bizar-dash/src/web/components/chat/ChatThread.tsx +29 -17
- package/bizar-dash/src/web/components/chat/FloatingComposer.tsx +7 -1
- package/bizar-dash/src/web/components/chat/InfoPanel.tsx +71 -6
- package/bizar-dash/src/web/components/chat/useChat.ts +751 -257
- package/bizar-dash/src/web/lib/api.ts +43 -0
- package/bizar-dash/src/web/main.tsx +1 -0
- package/bizar-dash/src/web/mobile/views/MobileChat.tsx +110 -35
- package/bizar-dash/src/web/styles/chat.css +135 -1
- package/bizar-dash/src/web/styles/main.css +46 -0
- package/bizar-dash/src/web/styles/minimax-usage.css +471 -0
- package/bizar-dash/src/web/styles/settings.css +418 -0
- package/bizar-dash/src/web/styles/skills.css +302 -0
- package/bizar-dash/src/web/styles/tasks.css +288 -0
- package/bizar-dash/src/web/views/Chat.tsx +276 -48
- package/bizar-dash/src/web/views/Config.tsx +3 -2065
- package/bizar-dash/src/web/views/MiniMaxUsage.tsx +620 -240
- package/bizar-dash/src/web/views/Settings.tsx +6 -0
- package/bizar-dash/src/web/views/Skills.tsx +208 -260
- package/bizar-dash/src/web/views/Tasks.tsx +348 -1119
- package/bizar-dash/tests/chat-session-create.test.mjs +391 -0
- package/bizar-dash/tests/chat-session-stream.test.mjs +308 -0
- package/bizar-dash/tests/env-vars-store.test.mjs +216 -0
- package/bizar-dash/tests/lightrag-defaults.node.test.mjs +118 -0
- package/bizar-dash/tests/minimax-chat-usage.test.mjs +178 -0
- package/bizar-dash/tests/minimax-usage-store.node.test.mjs +293 -0
- package/bizar-dash/tests/opencode-sessions-detail.test.mjs +12 -9
- package/bizar-dash/tests/providers-store-backup-keys.node.test.mjs +479 -3
- package/bizar-dash/tests/providers-store-search.node.test.mjs +166 -0
- package/bizar-dash/tests/skills-list.test.mjs +232 -0
- package/bizar-dash/tests/skills-search.test.mjs +222 -0
- package/bizar-dash/tests/tasks-create.test.mjs +187 -0
- package/bizar-dash/tests/update-check.test.mjs +127 -0
- package/bizar-dash/tests/update-run.test.mjs +266 -0
- package/cli/bin.mjs +345 -4
- package/cli/provision.mjs +118 -4
- package/config/agents/_shared/SKILLS.md +109 -0
- package/package.json +1 -1
- package/bizar-dash/dist/assets/main-BKXEqU1w.css +0 -1
- package/bizar-dash/dist/assets/main-EK_fzXn_.js +0 -352
- package/bizar-dash/dist/assets/main-EK_fzXn_.js.map +0 -1
- package/bizar-dash/dist/assets/mobile-Dl1q7Cyq.js +0 -354
- package/bizar-dash/dist/assets/mobile-Dl1q7Cyq.js.map +0 -1
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
// src/lib/api.ts — REST client. Single instance, type-safe wrappers.
|
|
2
2
|
//
|
|
3
|
+
// v3.6.2 — Token URL pickup for reverse-proxy / Tailscale Serve access.
|
|
4
|
+
// When the dashboard is accessed via Tailscale Serve (or any reverse
|
|
5
|
+
// proxy) the browser runs on a different origin than localhost. The server
|
|
6
|
+
// sees the remote client through the local proxy and requires auth.
|
|
7
|
+
// The `?token=…` URL param lets operators share a direct link that
|
|
8
|
+
// automatically installs the token into localStorage so the dashboard
|
|
9
|
+
// "just works" after the first paste — no separate localhost tab needed.
|
|
10
|
+
//
|
|
3
11
|
// v3.6.1 — Authentication is now loopback-aware on the server side.
|
|
4
12
|
// The browser makes API calls over 127.0.0.1 (or via Tailscale serve
|
|
5
13
|
// proxying to 127.0.0.1), and the server auto-trusts loopback
|
|
@@ -53,6 +61,35 @@ class ApiClient {
|
|
|
53
61
|
}
|
|
54
62
|
}
|
|
55
63
|
|
|
64
|
+
/**
|
|
65
|
+
* v3.6.2 — Check the URL search params for a `token` value and
|
|
66
|
+
* persist it into localStorage if found. Strips the param from the
|
|
67
|
+
* URL via `history.replaceState` so the token doesn't leak into
|
|
68
|
+
* browser history or shared links.
|
|
69
|
+
*
|
|
70
|
+
* Returns `true` if a token was found and saved, `false` otherwise.
|
|
71
|
+
* Safe to call multiple times (subsequent calls with no token in URL
|
|
72
|
+
* return `false` and are no-ops).
|
|
73
|
+
*/
|
|
74
|
+
pickupTokenFromUrl(): boolean {
|
|
75
|
+
try {
|
|
76
|
+
const params = new URLSearchParams(window.location.search);
|
|
77
|
+
const tok = params.get('token');
|
|
78
|
+
if (!tok) return false;
|
|
79
|
+
this.setToken(tok);
|
|
80
|
+
// Remove the token param from the URL without a page reload.
|
|
81
|
+
params.delete('token');
|
|
82
|
+
const newSearch = params.toString();
|
|
83
|
+
const newUrl = newSearch
|
|
84
|
+
? `${window.location.pathname}?${newSearch}`
|
|
85
|
+
: window.location.pathname;
|
|
86
|
+
history.replaceState(null, '', newUrl);
|
|
87
|
+
return true;
|
|
88
|
+
} catch {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
56
93
|
/** Build the URL with the token appended as ?token=… if present. */
|
|
57
94
|
urlWithToken(path: string): string {
|
|
58
95
|
const url = this.base + path;
|
|
@@ -180,6 +217,12 @@ class ApiClient {
|
|
|
180
217
|
}
|
|
181
218
|
|
|
182
219
|
export const api = new ApiClient();
|
|
220
|
+
|
|
221
|
+
// v3.6.2 — Auto-pickup token from URL on module load so the dashboard
|
|
222
|
+
// works through reverse proxies (Tailscale Serve, nginx, etc.) without
|
|
223
|
+
// needing a separate localhost tab.
|
|
224
|
+
api.pickupTokenFromUrl();
|
|
225
|
+
|
|
183
226
|
export { ApiClient, TOKEN_KEY };
|
|
184
227
|
|
|
185
228
|
/**
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
// src/web/mobile/views/MobileChat.tsx — mobile
|
|
2
|
-
//
|
|
1
|
+
// src/web/mobile/views/MobileChat.tsx — mobile chat (v4.2.5).
|
|
2
|
+
//
|
|
3
|
+
// v4.2.5 — matches Chat.tsx overhaul: opencode session-create via the
|
|
4
|
+
// new endpoint, source-routed composer (opencode send vs. local chat),
|
|
5
|
+
// source indicator badge, rename / delete / export on the info panel,
|
|
6
|
+
// and matching busy flags.
|
|
3
7
|
|
|
4
8
|
import { useEffect, useRef, useState } from 'react';
|
|
5
9
|
import { ChatTopBar } from '../../components/chat/ChatTopBar';
|
|
@@ -22,28 +26,41 @@ interface Props {
|
|
|
22
26
|
onClearTaskId?: () => void;
|
|
23
27
|
}
|
|
24
28
|
|
|
25
|
-
export function MobileChat({
|
|
29
|
+
export function MobileChat({
|
|
30
|
+
snapshot,
|
|
31
|
+
settings,
|
|
32
|
+
setActiveTab,
|
|
33
|
+
initialTaskId,
|
|
34
|
+
onClearTaskId,
|
|
35
|
+
}: Props) {
|
|
26
36
|
const toast = useToast();
|
|
27
37
|
const modal = useModal();
|
|
28
38
|
|
|
29
39
|
const chat = useChat(snapshot, settings, initialTaskId ?? '');
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
chat.setToast({
|
|
42
|
+
error: (msg: string) => toast.error(msg),
|
|
43
|
+
success: (msg: string) => toast.success(msg),
|
|
44
|
+
info: (msg: string) => toast.info(msg),
|
|
45
|
+
warning: (msg: string) => toast.warning(msg),
|
|
46
|
+
});
|
|
47
|
+
}, [chat, toast]);
|
|
30
48
|
|
|
31
49
|
const [text, setText] = useState('');
|
|
32
50
|
const [agent, setAgent] = useState(settings.defaultAgent || 'odin');
|
|
33
51
|
const [model, setModel] = useState(settings.defaultModel || '');
|
|
34
52
|
const [attachments, setAttachments] = useState<string[]>([]);
|
|
35
|
-
const [creating, setCreating] = useState(false);
|
|
36
53
|
const [sessionsOpen, setSessionsOpen] = useState(false);
|
|
37
54
|
const [infoOpen, setInfoOpen] = useState(false);
|
|
38
55
|
|
|
39
56
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
|
40
57
|
|
|
41
58
|
const { allCommands, suggestions, setQuery } = useSlashCommands(snapshot);
|
|
42
|
-
|
|
43
|
-
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
setQuery(text);
|
|
61
|
+
}, [text, setQuery]);
|
|
44
62
|
|
|
45
63
|
const onAttach = () => fileInputRef.current?.click();
|
|
46
|
-
|
|
47
64
|
const onFiles = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
48
65
|
const files = e.target.files;
|
|
49
66
|
if (!files) return;
|
|
@@ -56,30 +73,19 @@ export function MobileChat({ snapshot, settings, setActiveTab, initialTaskId, on
|
|
|
56
73
|
if (fileInputRef.current) fileInputRef.current.value = '';
|
|
57
74
|
};
|
|
58
75
|
|
|
59
|
-
const handleSend = () => {
|
|
76
|
+
const handleSend = async () => {
|
|
60
77
|
const msg = text.trim();
|
|
61
78
|
if (!msg) return;
|
|
62
79
|
setText('');
|
|
63
80
|
setQuery('');
|
|
64
|
-
chat.onSend(msg, agent, model, attachments);
|
|
81
|
+
const result = await chat.onSend(msg, agent, model, attachments);
|
|
82
|
+
if (result.ok) chat.jumpToLatest();
|
|
65
83
|
};
|
|
66
84
|
|
|
67
85
|
const handleCreateSession = async () => {
|
|
68
|
-
if (
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
setCreating(true);
|
|
74
|
-
try {
|
|
75
|
-
const created = await fetch('/chat/sessions', { method: 'POST' }).then((r) => r.json());
|
|
76
|
-
chat.loadChat(created.id);
|
|
77
|
-
toast.success(`Session ${created.id} created.`);
|
|
78
|
-
} catch (err) {
|
|
79
|
-
toast.error(`Create failed: ${(err as Error).message}`);
|
|
80
|
-
} finally {
|
|
81
|
-
setCreating(false);
|
|
82
|
-
}
|
|
86
|
+
if (chat.busy.create) return;
|
|
87
|
+
await chat.onCreateSession();
|
|
88
|
+
setSessionsOpen(false);
|
|
83
89
|
};
|
|
84
90
|
|
|
85
91
|
const handleDelete = (idx: number) => {
|
|
@@ -88,7 +94,9 @@ export function MobileChat({ snapshot, settings, setActiveTab, initialTaskId, on
|
|
|
88
94
|
children: <p style={{ margin: 0 }}>This action cannot be undone.</p>,
|
|
89
95
|
footer: (
|
|
90
96
|
<div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end' }}>
|
|
91
|
-
<Button variant="secondary" size="sm" onClick={() => modal.close()}>
|
|
97
|
+
<Button variant="secondary" size="sm" onClick={() => modal.close()}>
|
|
98
|
+
Cancel
|
|
99
|
+
</Button>
|
|
92
100
|
<Button
|
|
93
101
|
variant="danger"
|
|
94
102
|
size="sm"
|
|
@@ -104,6 +112,34 @@ export function MobileChat({ snapshot, settings, setActiveTab, initialTaskId, on
|
|
|
104
112
|
});
|
|
105
113
|
};
|
|
106
114
|
|
|
115
|
+
const handleDeleteSession = (id: string, title: string) => {
|
|
116
|
+
modal.open({
|
|
117
|
+
title: 'Delete session?',
|
|
118
|
+
children: (
|
|
119
|
+
<p style={{ margin: 0 }}>
|
|
120
|
+
Delete <strong>{title}</strong>? This cannot be undone.
|
|
121
|
+
</p>
|
|
122
|
+
),
|
|
123
|
+
footer: (
|
|
124
|
+
<div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end' }}>
|
|
125
|
+
<Button variant="secondary" size="sm" onClick={() => modal.close()}>
|
|
126
|
+
Cancel
|
|
127
|
+
</Button>
|
|
128
|
+
<Button
|
|
129
|
+
variant="danger"
|
|
130
|
+
size="sm"
|
|
131
|
+
onClick={async () => {
|
|
132
|
+
modal.close();
|
|
133
|
+
await chat.deleteSession(id);
|
|
134
|
+
}}
|
|
135
|
+
>
|
|
136
|
+
Delete
|
|
137
|
+
</Button>
|
|
138
|
+
</div>
|
|
139
|
+
),
|
|
140
|
+
});
|
|
141
|
+
};
|
|
142
|
+
|
|
107
143
|
return (
|
|
108
144
|
<div className="chat-shell">
|
|
109
145
|
<ChatTopBar
|
|
@@ -116,7 +152,9 @@ export function MobileChat({ snapshot, settings, setActiveTab, initialTaskId, on
|
|
|
116
152
|
onOpenOverview={() => setActiveTab?.('overview')}
|
|
117
153
|
/>
|
|
118
154
|
<div className="chat-body">
|
|
119
|
-
<aside
|
|
155
|
+
<aside
|
|
156
|
+
className={`chat-sessions ${!sessionsOpen ? 'chat-sessions-hidden' : ''}`}
|
|
157
|
+
>
|
|
120
158
|
<SessionList
|
|
121
159
|
sessions={chat.sessions}
|
|
122
160
|
opencodeSessions={chat.opencodeSessions}
|
|
@@ -126,19 +164,30 @@ export function MobileChat({ snapshot, settings, setActiveTab, initialTaskId, on
|
|
|
126
164
|
onCreateSession={handleCreateSession}
|
|
127
165
|
onSelectSession={chat.selectBizarSession}
|
|
128
166
|
onSelectOpencodeSession={(s) => chat.loadOpencodeSession(s.id)}
|
|
129
|
-
creating={
|
|
167
|
+
creating={chat.busy.create}
|
|
130
168
|
/>
|
|
131
169
|
</aside>
|
|
132
170
|
|
|
133
171
|
<main className="chat-main">
|
|
134
172
|
<ChatThread
|
|
135
|
-
messages={
|
|
173
|
+
messages={
|
|
174
|
+
chat.activeSource === 'opencode'
|
|
175
|
+
? chat.opencodeMessages
|
|
176
|
+
: chat.bizarMessages
|
|
177
|
+
}
|
|
136
178
|
loading={chat.loading}
|
|
137
179
|
activeProject={snapshot.activeProject}
|
|
138
|
-
sessionId={
|
|
180
|
+
sessionId={
|
|
181
|
+
chat.activeSource === 'opencode'
|
|
182
|
+
? chat.activeOpencodeSessionId ?? chat.sessionId
|
|
183
|
+
: chat.sessionId
|
|
184
|
+
}
|
|
139
185
|
pinned={chat.pinned}
|
|
186
|
+
activeSource={chat.activeSource}
|
|
140
187
|
onPickSuggestion={(t) => setText(t)}
|
|
141
|
-
onCopy={(m) =>
|
|
188
|
+
onCopy={(m) =>
|
|
189
|
+
chat.copyMessage(m as Parameters<typeof chat.copyMessage>[0])
|
|
190
|
+
}
|
|
142
191
|
onDelete={handleDelete}
|
|
143
192
|
onTogglePin={chat.togglePin}
|
|
144
193
|
onRegenerate={chat.onRegenerate}
|
|
@@ -151,6 +200,7 @@ export function MobileChat({ snapshot, settings, setActiveTab, initialTaskId, on
|
|
|
151
200
|
text={text}
|
|
152
201
|
setText={setText}
|
|
153
202
|
sending={chat.sending}
|
|
203
|
+
activeSource={chat.activeSource}
|
|
154
204
|
onSend={handleSend}
|
|
155
205
|
attachments={attachments}
|
|
156
206
|
setAttachments={setAttachments}
|
|
@@ -161,22 +211,47 @@ export function MobileChat({ snapshot, settings, setActiveTab, initialTaskId, on
|
|
|
161
211
|
sessionsOpen={sessionsOpen}
|
|
162
212
|
infoOpen={infoOpen}
|
|
163
213
|
/>
|
|
164
|
-
<input
|
|
214
|
+
<input
|
|
215
|
+
ref={fileInputRef}
|
|
216
|
+
type="file"
|
|
217
|
+
multiple
|
|
218
|
+
style={{ display: 'none' }}
|
|
219
|
+
onChange={onFiles}
|
|
220
|
+
/>
|
|
165
221
|
</main>
|
|
166
222
|
|
|
167
|
-
<aside
|
|
223
|
+
<aside
|
|
224
|
+
className={`chat-info ${!infoOpen ? 'chat-info-hidden' : ''}`}
|
|
225
|
+
>
|
|
168
226
|
<InfoPanel
|
|
169
|
-
sessionId={
|
|
170
|
-
|
|
227
|
+
sessionId={
|
|
228
|
+
chat.activeSource === 'opencode'
|
|
229
|
+
? chat.activeOpencodeSessionId ?? chat.sessionId
|
|
230
|
+
: chat.sessionId
|
|
231
|
+
}
|
|
232
|
+
messages={
|
|
233
|
+
chat.activeSource === 'opencode'
|
|
234
|
+
? chat.opencodeMessages
|
|
235
|
+
: chat.bizarMessages
|
|
236
|
+
}
|
|
171
237
|
pinned={chat.pinned}
|
|
172
238
|
agent={agent}
|
|
173
239
|
model={model}
|
|
174
240
|
agents={snapshot.agents || []}
|
|
175
241
|
mcps={snapshot.mcps || []}
|
|
176
242
|
allCommands={allCommands}
|
|
243
|
+
activeSource={chat.activeSource}
|
|
244
|
+
onDelete={() => {
|
|
245
|
+
const id =
|
|
246
|
+
chat.activeSource === 'opencode'
|
|
247
|
+
? chat.activeOpencodeSessionId
|
|
248
|
+
: chat.sessionId;
|
|
249
|
+
if (!id) return;
|
|
250
|
+
handleDeleteSession(id, id);
|
|
251
|
+
}}
|
|
177
252
|
/>
|
|
178
253
|
</aside>
|
|
179
254
|
</div>
|
|
180
255
|
</div>
|
|
181
256
|
);
|
|
182
|
-
}
|
|
257
|
+
}
|
|
@@ -1598,4 +1598,138 @@
|
|
|
1598
1598
|
font-size: 0.8125rem; color: var(--text-muted); margin: 0;
|
|
1599
1599
|
max-width: 320px;
|
|
1600
1600
|
}
|
|
1601
|
-
.chat-empty-state-action { margin-top: 0.5rem; }
|
|
1601
|
+
.chat-empty-state-action { margin-top: 0.5rem; }
|
|
1602
|
+
|
|
1603
|
+
/* ============================================================
|
|
1604
|
+
v4.2.5 — CHAT OVERHAUL: source badge, info-actions, error
|
|
1605
|
+
row, and source-tinted composer. These are additive — they
|
|
1606
|
+
don't override any of the legacy rules above.
|
|
1607
|
+
============================================================ */
|
|
1608
|
+
|
|
1609
|
+
/* ---- source badge (opencode / bizar chat) ---- */
|
|
1610
|
+
.chat-source-badge {
|
|
1611
|
+
display: inline-flex; align-items: center;
|
|
1612
|
+
padding: 2px 8px;
|
|
1613
|
+
border-radius: var(--radius-pill);
|
|
1614
|
+
font: 10px/1 var(--font-mono);
|
|
1615
|
+
letter-spacing: 0.04em;
|
|
1616
|
+
text-transform: uppercase;
|
|
1617
|
+
border: 1px solid transparent;
|
|
1618
|
+
}
|
|
1619
|
+
.chat-source-opencode {
|
|
1620
|
+
background: rgba(139, 92, 246, 0.12);
|
|
1621
|
+
color: var(--accent);
|
|
1622
|
+
border-color: rgba(139, 92, 246, 0.4);
|
|
1623
|
+
}
|
|
1624
|
+
.chat-source-bizar {
|
|
1625
|
+
background: var(--bg-2);
|
|
1626
|
+
color: var(--text-muted);
|
|
1627
|
+
border-color: var(--border);
|
|
1628
|
+
}
|
|
1629
|
+
.chat-source-none {
|
|
1630
|
+
background: var(--bg-2);
|
|
1631
|
+
color: var(--text-muted);
|
|
1632
|
+
border-color: var(--border);
|
|
1633
|
+
opacity: 0.7;
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1636
|
+
/* ---- thread-head title row (so badge sits inline) ---- */
|
|
1637
|
+
.chat-thread-title-row {
|
|
1638
|
+
display: flex; align-items: center; gap: 8px;
|
|
1639
|
+
flex-wrap: wrap;
|
|
1640
|
+
}
|
|
1641
|
+
|
|
1642
|
+
/* ---- thread error row (SSE/upstream failures) ---- */
|
|
1643
|
+
.chat-thread-error {
|
|
1644
|
+
margin-top: 4px;
|
|
1645
|
+
padding: 4px 10px;
|
|
1646
|
+
background: rgba(248, 81, 73, 0.08);
|
|
1647
|
+
border: 1px solid rgba(248, 81, 73, 0.4);
|
|
1648
|
+
border-radius: var(--radius-sm);
|
|
1649
|
+
font: 11px/1.3 var(--font-mono);
|
|
1650
|
+
color: var(--error);
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
/* ---- info-panel section heads + actions ---- */
|
|
1654
|
+
.chat-info-section-head {
|
|
1655
|
+
display: flex; align-items: center;
|
|
1656
|
+
margin-bottom: 8px;
|
|
1657
|
+
}
|
|
1658
|
+
.chat-info-value {
|
|
1659
|
+
font: 13px/1.4 var(--font-sans);
|
|
1660
|
+
color: var(--text);
|
|
1661
|
+
}
|
|
1662
|
+
.chat-info-actions {
|
|
1663
|
+
display: flex; flex-wrap: wrap; gap: 6px;
|
|
1664
|
+
margin-top: 8px;
|
|
1665
|
+
}
|
|
1666
|
+
.chat-info-actions .btn {
|
|
1667
|
+
font: 11px/1 var(--font-sans);
|
|
1668
|
+
padding: 6px 10px;
|
|
1669
|
+
border: 1px solid var(--border);
|
|
1670
|
+
background: var(--bg);
|
|
1671
|
+
color: var(--text);
|
|
1672
|
+
border-radius: var(--radius-sm);
|
|
1673
|
+
cursor: pointer;
|
|
1674
|
+
display: inline-flex; align-items: center; gap: 4px;
|
|
1675
|
+
transition: background var(--motion-fast) var(--motion-ease);
|
|
1676
|
+
}
|
|
1677
|
+
.chat-info-actions .btn:hover:not(:disabled) {
|
|
1678
|
+
background: var(--bg-1);
|
|
1679
|
+
}
|
|
1680
|
+
.chat-info-actions .btn:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
1681
|
+
.chat-info-actions .btn-danger { color: var(--error); border-color: rgba(248, 81, 73, 0.4); }
|
|
1682
|
+
.chat-info-actions .btn-danger:hover:not(:disabled) {
|
|
1683
|
+
background: rgba(248, 81, 73, 0.08);
|
|
1684
|
+
}
|
|
1685
|
+
|
|
1686
|
+
/* ---- btn-ghost tokens (also defined in main.css but we re-stamp here for safety) ---- */
|
|
1687
|
+
.btn-ghost {
|
|
1688
|
+
display: inline-flex; align-items: center; gap: 4px;
|
|
1689
|
+
padding: 4px 8px;
|
|
1690
|
+
background: transparent;
|
|
1691
|
+
border: 1px solid transparent;
|
|
1692
|
+
border-radius: var(--radius-sm);
|
|
1693
|
+
color: var(--text-muted);
|
|
1694
|
+
font: 11px/1 var(--font-mono);
|
|
1695
|
+
cursor: pointer;
|
|
1696
|
+
transition: background var(--motion-fast) var(--motion-ease),
|
|
1697
|
+
color var(--motion-fast) var(--motion-ease);
|
|
1698
|
+
}
|
|
1699
|
+
.btn-ghost:hover:not(:disabled) { background: var(--bg-1); color: var(--text); }
|
|
1700
|
+
.btn-ghost:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
1701
|
+
.btn-ghost.btn-danger { color: var(--error); }
|
|
1702
|
+
.btn-ghost.btn-sm { padding: 4px 6px; font-size: 11px; }
|
|
1703
|
+
|
|
1704
|
+
/* ---- composer: source-tinted pill border + hint line ---- */
|
|
1705
|
+
.chat-composer-source-opencode .chat-composer-pill {
|
|
1706
|
+
border-color: rgba(139, 92, 246, 0.35);
|
|
1707
|
+
}
|
|
1708
|
+
.chat-composer-source-opencode .chat-composer-pill:focus-within {
|
|
1709
|
+
border-color: var(--accent);
|
|
1710
|
+
}
|
|
1711
|
+
.chat-composer-source-opencode::before {
|
|
1712
|
+
content: '';
|
|
1713
|
+
position: absolute;
|
|
1714
|
+
top: 0; left: 0; right: 0;
|
|
1715
|
+
height: 1px;
|
|
1716
|
+
background: linear-gradient(90deg, transparent, var(--accent), transparent);
|
|
1717
|
+
opacity: 0.6;
|
|
1718
|
+
}
|
|
1719
|
+
.chat-composer-wrap {
|
|
1720
|
+
position: relative;
|
|
1721
|
+
}
|
|
1722
|
+
.chat-composer-source-hint {
|
|
1723
|
+
margin-left: auto;
|
|
1724
|
+
font: 10px/1 var(--font-mono);
|
|
1725
|
+
letter-spacing: 0.04em;
|
|
1726
|
+
text-transform: uppercase;
|
|
1727
|
+
color: var(--text-muted);
|
|
1728
|
+
opacity: 0.8;
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1731
|
+
/* ---- legacy composer pointer-events fix ---- */
|
|
1732
|
+
.chat-composer-wrap.legacy {
|
|
1733
|
+
pointer-events: none;
|
|
1734
|
+
}
|
|
1735
|
+
.chat-composer-wrap.legacy > * { pointer-events: auto; }
|
|
@@ -166,6 +166,18 @@ pre,
|
|
|
166
166
|
--space-10: 40px;
|
|
167
167
|
--space-12: 48px;
|
|
168
168
|
|
|
169
|
+
/* v4.6.0 — Semantic spacing aliases. These mirror the existing
|
|
170
|
+
--space-* numeric scale so existing rules stay untouched, and
|
|
171
|
+
new code can pick the alias that fits the intent. Use whichever
|
|
172
|
+
reads clearer at the call site; they resolve to the same pixel
|
|
173
|
+
values. Goal: kill the "is this 12 or 16?" guessing in
|
|
174
|
+
view-level padding. */
|
|
175
|
+
--spacing-xs: var(--space-1); /* 4px — micro gap, icon-to-text */
|
|
176
|
+
--spacing-sm: var(--space-2); /* 8px — tight stack, between rows */
|
|
177
|
+
--spacing-md: var(--space-3); /* 12px — default card padding */
|
|
178
|
+
--spacing-lg: var(--space-4); /* 16px — section padding */
|
|
179
|
+
--spacing-xl: var(--space-6); /* 24px — page-level padding */
|
|
180
|
+
|
|
169
181
|
/* Radius */
|
|
170
182
|
--radius-sm: 4px;
|
|
171
183
|
--radius: 8px;
|
|
@@ -417,6 +429,34 @@ pre,
|
|
|
417
429
|
font-size: 12px;
|
|
418
430
|
}
|
|
419
431
|
|
|
432
|
+
/* v3.6.2 — Token-entry form on boot-error screen */
|
|
433
|
+
.token-entry-form {
|
|
434
|
+
margin: var(--space-4) 0;
|
|
435
|
+
display: flex;
|
|
436
|
+
flex-direction: column;
|
|
437
|
+
gap: var(--space-2);
|
|
438
|
+
}
|
|
439
|
+
.token-entry-row {
|
|
440
|
+
display: flex;
|
|
441
|
+
gap: var(--space-2);
|
|
442
|
+
align-items: center;
|
|
443
|
+
}
|
|
444
|
+
.token-entry-row .input {
|
|
445
|
+
flex: 1;
|
|
446
|
+
min-width: 0;
|
|
447
|
+
}
|
|
448
|
+
.token-entry-hint {
|
|
449
|
+
margin: 0;
|
|
450
|
+
font-size: 12px;
|
|
451
|
+
color: var(--text-dim);
|
|
452
|
+
}
|
|
453
|
+
.token-entry-hint code {
|
|
454
|
+
background: var(--bg);
|
|
455
|
+
padding: 1px 4px;
|
|
456
|
+
border-radius: var(--radius-sm);
|
|
457
|
+
font-size: 11px;
|
|
458
|
+
}
|
|
459
|
+
|
|
420
460
|
/* ─── Topbar ───────────────────────────────────────────────────────── */
|
|
421
461
|
|
|
422
462
|
.topbar {
|
|
@@ -5581,6 +5621,12 @@ html[data-compact-mode="true"] {
|
|
|
5581
5621
|
--space-4: 12px;
|
|
5582
5622
|
--space-5: 16px;
|
|
5583
5623
|
--space-6: 20px;
|
|
5624
|
+
/* Spacing aliases track the scaled numeric scale. */
|
|
5625
|
+
--spacing-xs: var(--space-1);
|
|
5626
|
+
--spacing-sm: var(--space-2);
|
|
5627
|
+
--spacing-md: var(--space-3);
|
|
5628
|
+
--spacing-lg: var(--space-4);
|
|
5629
|
+
--spacing-xl: var(--space-6);
|
|
5584
5630
|
}
|
|
5585
5631
|
html[data-compact-mode="true"] .kanban-col-header { padding: 4px; }
|
|
5586
5632
|
html[data-compact-mode="true"] .task-card { padding: 6px; }
|