anentrypoint-design 0.0.368 → 0.0.370
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/chat.css +128 -0
- package/dist/247420.css +454 -1
- package/dist/247420.js +27 -27
- package/package.json +2 -8
- package/src/components/chat-message-parts.js +42 -4
- package/src/components/chat-minimap.js +309 -0
- package/src/components/chat.js +2 -1
- package/src/components/editor-primitives.js +41 -14
- package/src/components/files-modals.js +44 -4
- package/src/components/git-status.js +22 -6
- package/src/components/interaction-primitives.js +27 -0
- package/src/components/models-config.js +229 -0
- package/src/components/plugins-config.js +154 -0
- package/src/components/sessions.js +138 -38
- package/src/components/skills-config.js +188 -0
- package/src/components/voice.js +41 -0
- package/src/components.js +12 -2
- package/src/css/app-shell/chat-polish.css +25 -0
- package/src/css/app-shell/files.css +18 -0
- package/src/css/app-shell/models-config.css +93 -0
- package/src/css/app-shell/plugins-config.css +139 -0
- package/src/css/app-shell/skills-config.css +27 -0
- package/src/file-mention.js +142 -0
- package/src/index.js +6 -0
- package/src/math.js +158 -0
- package/src/mermaid.js +105 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
// SkillsConfig — skill list + detail panel, ported from pi-web's
|
|
2
|
+
// SkillsConfig.tsx UX (modal, sidebar list grouped/searchable, detail pane
|
|
3
|
+
// with enable/disable toggle) but rebuilt over freddie's real skill contract,
|
|
4
|
+
// not pi-web's installable-package model:
|
|
5
|
+
//
|
|
6
|
+
// { file, name, description, frontmatter, body, platforms? }
|
|
7
|
+
//
|
|
8
|
+
// (see freddie's AGENTS.md — `src/skills/index.js::listSkills/loadSkill`,
|
|
9
|
+
// `skills/<category>/<name>/SKILL.md` with YAML frontmatter). There is no
|
|
10
|
+
// install/update/search-registry flow here: freddie skills are local
|
|
11
|
+
// filesystem discovery only (`skills/`, `~/.freddie/skills/`), so the only
|
|
12
|
+
// host-facing action is enable/disable. `category` (derived from the skill's
|
|
13
|
+
// path — the directory directly under a `skills/` root) replaces pi-web's
|
|
14
|
+
// source/scope grouping (project/global/path), and `platforms` renders as
|
|
15
|
+
// chips in place of pi-web's version/update-check UI.
|
|
16
|
+
//
|
|
17
|
+
// Usage (consumer wires its own state/fetch, this is presentation-only):
|
|
18
|
+
// SkillsConfig({ skills, selected, onSelect, onToggle, onClose })
|
|
19
|
+
//
|
|
20
|
+
// Props:
|
|
21
|
+
// skills : [{ file, name, description, category?, platforms?, enabled, frontmatter?, body? }]
|
|
22
|
+
// category is derived from `file`'s path when not passed explicitly
|
|
23
|
+
// (segment directly under the nearest `skills` directory).
|
|
24
|
+
// enabled drives the toggle and the sidebar status dot.
|
|
25
|
+
// selected : name of the currently-selected skill, or null
|
|
26
|
+
// loading : bool — sidebar shows a loading row instead of the list
|
|
27
|
+
// error : string|null — sidebar shows this instead of the list
|
|
28
|
+
// busyName : name of the skill currently mid-toggle, or null
|
|
29
|
+
// query : current search text (string) — controlled by the consumer
|
|
30
|
+
// onQuery : (text) => void — fired on search input
|
|
31
|
+
// onSelect : (name) => void
|
|
32
|
+
// onToggle : (skill) => void — fired with the full skill row to flip enabled
|
|
33
|
+
// onClose : () => void
|
|
34
|
+
//
|
|
35
|
+
// No decorative glyphs beyond the kit's Icon SVGs — status communicated by a
|
|
36
|
+
// tone dot + text label, never color alone.
|
|
37
|
+
|
|
38
|
+
import * as webjsx from '../../vendor/webjsx/index.js';
|
|
39
|
+
import { Icon } from './shell.js';
|
|
40
|
+
import { SearchInput } from './content.js';
|
|
41
|
+
const h = webjsx.createElement;
|
|
42
|
+
|
|
43
|
+
const CATEGORY_ORDER = ['software-development', 'ops', 'data', 'planning', 'creative'];
|
|
44
|
+
|
|
45
|
+
function deriveCategory(skill) {
|
|
46
|
+
if (skill.category) return skill.category;
|
|
47
|
+
const file = skill.file || '';
|
|
48
|
+
const parts = file.split(/[/\\]/).filter(Boolean);
|
|
49
|
+
const idx = parts.lastIndexOf('skills');
|
|
50
|
+
if (idx >= 0 && parts.length > idx + 1) return parts[idx + 1];
|
|
51
|
+
return 'other';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function statusTone(skill) {
|
|
55
|
+
return skill.enabled === false ? 'neutral' : 'add';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function statusLabel(skill) {
|
|
59
|
+
return skill.enabled === false ? 'disabled' : 'enabled';
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function matchesQuery(skill, query) {
|
|
63
|
+
if (!query) return true;
|
|
64
|
+
const q = query.toLowerCase();
|
|
65
|
+
return (skill.name || '').toLowerCase().includes(q) ||
|
|
66
|
+
(skill.description || '').toLowerCase().includes(q);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function SkillSidebarRow({ skill, active, busy, onSelect }) {
|
|
70
|
+
return h('button', {
|
|
71
|
+
type: 'button',
|
|
72
|
+
class: 'ds-plugins-row' + (active ? ' active' : ''),
|
|
73
|
+
onclick: () => onSelect(skill.name),
|
|
74
|
+
'aria-pressed': active ? 'true' : 'false',
|
|
75
|
+
'aria-label': skill.name + ': ' + statusLabel(skill),
|
|
76
|
+
},
|
|
77
|
+
h('span', { class: 'ds-plugins-dot tone-' + statusTone(skill), 'aria-hidden': 'true' }),
|
|
78
|
+
h('span', { class: 'ds-plugins-row-body' },
|
|
79
|
+
h('span', { class: 'ds-plugins-row-name' }, skill.name),
|
|
80
|
+
skill.description
|
|
81
|
+
? h('span', { class: 'ds-plugins-row-meta' }, skill.description)
|
|
82
|
+
: null),
|
|
83
|
+
busy ? h('span', { class: 'ds-plugins-row-busy' }, '…') : null);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function SkillDetail({ skill, busy, onToggle }) {
|
|
87
|
+
if (!skill) {
|
|
88
|
+
return h('div', { class: 'ds-plugins-empty', role: 'status' },
|
|
89
|
+
h('span', { 'aria-hidden': 'true' }, Icon('circle-dot', { size: 22 })),
|
|
90
|
+
h('span', {}, 'Select a skill'));
|
|
91
|
+
}
|
|
92
|
+
const platforms = Array.isArray(skill.platforms) ? skill.platforms : [];
|
|
93
|
+
return h('div', { class: 'ds-plugins-detail' },
|
|
94
|
+
h('div', { class: 'ds-plugins-detail-head' },
|
|
95
|
+
h('div', { class: 'ds-plugins-detail-title' },
|
|
96
|
+
h('span', { class: 'ds-plugins-dot tone-' + statusTone(skill), 'aria-hidden': 'true' }),
|
|
97
|
+
h('span', { class: 'name' }, skill.name)),
|
|
98
|
+
h('button', {
|
|
99
|
+
type: 'button',
|
|
100
|
+
class: 'ds-plugins-toggle' + (skill.enabled !== false ? ' on' : ''),
|
|
101
|
+
disabled: busy ? true : null,
|
|
102
|
+
onclick: () => onToggle && onToggle(skill),
|
|
103
|
+
'aria-pressed': skill.enabled !== false ? 'true' : 'false',
|
|
104
|
+
'aria-label': skill.enabled !== false ? 'Disable skill' : 'Enable skill',
|
|
105
|
+
}, h('span', { class: 'ds-plugins-toggle-knob' }))),
|
|
106
|
+
skill.description
|
|
107
|
+
? h('div', { class: 'ds-skills-description' }, skill.description)
|
|
108
|
+
: null,
|
|
109
|
+
h('div', { class: 'ds-plugins-fact-grid' },
|
|
110
|
+
h('div', { class: 'ds-plugins-fact-label' }, 'status'),
|
|
111
|
+
h('div', { class: 'ds-plugins-fact-value tone-text-' + statusTone(skill) }, statusLabel(skill)),
|
|
112
|
+
h('div', { class: 'ds-plugins-fact-label' }, 'category'),
|
|
113
|
+
h('div', { class: 'ds-plugins-fact-value' }, deriveCategory(skill)),
|
|
114
|
+
skill.file ? h('div', { class: 'ds-plugins-fact-label' }, 'path') : null,
|
|
115
|
+
skill.file ? h('div', { class: 'ds-plugins-fact-value ds-plugins-mono' }, skill.file) : null),
|
|
116
|
+
h('div', { class: 'ds-plugins-requires' },
|
|
117
|
+
h('div', { class: 'ds-plugins-group-label' }, 'platforms'),
|
|
118
|
+
platforms.length
|
|
119
|
+
? h('div', { class: 'ds-plugins-requires-list' },
|
|
120
|
+
...platforms.map((p) => h('span', { key: p, class: 'ds-plugins-chip' }, p)))
|
|
121
|
+
: h('div', { class: 'ds-plugins-requires-empty' }, 'all platforms')),
|
|
122
|
+
skill.body
|
|
123
|
+
? h('div', { class: 'ds-skills-body-group' },
|
|
124
|
+
h('div', { class: 'ds-plugins-group-label' }, 'body preview'),
|
|
125
|
+
h('pre', { class: 'ds-skills-body-preview' }, skill.body.slice(0, 2000)))
|
|
126
|
+
: null);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export function SkillsConfig({
|
|
130
|
+
skills = [],
|
|
131
|
+
selected = null,
|
|
132
|
+
loading = false,
|
|
133
|
+
error = null,
|
|
134
|
+
busyName = null,
|
|
135
|
+
query = '',
|
|
136
|
+
onQuery,
|
|
137
|
+
onSelect,
|
|
138
|
+
onToggle,
|
|
139
|
+
onClose,
|
|
140
|
+
} = {}) {
|
|
141
|
+
const selectedSkill = skills.find((s) => s.name === selected) || null;
|
|
142
|
+
const filtered = skills.filter((s) => matchesQuery(s, query));
|
|
143
|
+
|
|
144
|
+
// Group filtered skills by category, ordering freddie's five bundled
|
|
145
|
+
// categories first, then any others (custom/`~/.freddie/skills/`) alphabetically.
|
|
146
|
+
const byCategory = new Map();
|
|
147
|
+
for (const s of filtered) {
|
|
148
|
+
const cat = deriveCategory(s);
|
|
149
|
+
if (!byCategory.has(cat)) byCategory.set(cat, []);
|
|
150
|
+
byCategory.get(cat).push(s);
|
|
151
|
+
}
|
|
152
|
+
const otherCats = [...byCategory.keys()].filter((c) => !CATEGORY_ORDER.includes(c)).sort();
|
|
153
|
+
const orderedCats = [...CATEGORY_ORDER.filter((c) => byCategory.has(c)), ...otherCats];
|
|
154
|
+
|
|
155
|
+
const sidebarBody = loading
|
|
156
|
+
? h('div', { class: 'ds-plugins-sidebar-status' }, 'Loading…')
|
|
157
|
+
: error
|
|
158
|
+
? h('div', { class: 'ds-plugins-sidebar-status ds-plugins-status-error' }, error)
|
|
159
|
+
: filtered.length === 0
|
|
160
|
+
? h('div', { class: 'ds-plugins-sidebar-status' }, skills.length === 0 ? 'No skills found' : 'No skills match your search')
|
|
161
|
+
: h('div', { class: 'ds-plugins-list', role: 'listbox', 'aria-label': 'skill list' },
|
|
162
|
+
...orderedCats.map((cat) => h('div', { key: 'grp-' + cat, class: 'ds-skills-group' },
|
|
163
|
+
h('div', { class: 'ds-skills-group-label' }, cat),
|
|
164
|
+
...byCategory.get(cat).map((s) => SkillSidebarRow({
|
|
165
|
+
key: s.name,
|
|
166
|
+
skill: s,
|
|
167
|
+
active: selected === s.name,
|
|
168
|
+
busy: busyName === s.name,
|
|
169
|
+
onSelect,
|
|
170
|
+
})))));
|
|
171
|
+
|
|
172
|
+
const footerText = filtered.length + ' skill' + (filtered.length === 1 ? '' : 's') +
|
|
173
|
+
(query ? ' (of ' + skills.length + ')' : '');
|
|
174
|
+
|
|
175
|
+
return h('div', { class: 'ds-plugins-overlay', onclick: (e) => { if (e.target === e.currentTarget && onClose) onClose(); } },
|
|
176
|
+
h('div', { class: 'ds-plugins-modal', role: 'dialog', 'aria-label': 'Skills' },
|
|
177
|
+
h('div', { class: 'ds-plugins-header' },
|
|
178
|
+
h('span', { class: 'ds-plugins-title' }, 'Skills'),
|
|
179
|
+
onClose ? h('button', { type: 'button', class: 'ds-plugins-close', onclick: onClose, 'aria-label': 'Close' }, '×') : null),
|
|
180
|
+
h('div', { class: 'ds-skills-search-row' },
|
|
181
|
+
SearchInput({ value: query, placeholder: 'search skills…', onInput: onQuery, label: 'search skills' })),
|
|
182
|
+
h('div', { class: 'ds-plugins-body' },
|
|
183
|
+
h('div', { class: 'ds-plugins-sidebar' }, sidebarBody),
|
|
184
|
+
h('div', { class: 'ds-plugins-main' },
|
|
185
|
+
SkillDetail({ skill: selectedSkill, busy: busyName === (selectedSkill && selectedSkill.name), onToggle }))),
|
|
186
|
+
h('div', { class: 'ds-plugins-footer' },
|
|
187
|
+
h('span', { class: 'ds-plugins-footer-count' }, footerText))));
|
|
188
|
+
}
|
package/src/components/voice.js
CHANGED
|
@@ -5,6 +5,47 @@ import * as webjsx from '../../vendor/webjsx/index.js';
|
|
|
5
5
|
import { Icon } from './shell.js';
|
|
6
6
|
const h = webjsx.createElement;
|
|
7
7
|
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// playCompletionCue — short two-tone audio cue (e.g. "agent turn finished"),
|
|
10
|
+
// ported from pi-web's useAudio. This file otherwise covers voice-call UI
|
|
11
|
+
// (PTT/VAD/webcam/queue), not simple one-shot notification tones, so this is
|
|
12
|
+
// the missing piece rather than a duplicate. A single AudioContext is reused
|
|
13
|
+
// (module-scoped) so a browser autoplay-suspended context can be resumed
|
|
14
|
+
// instead of leaking a fresh context per call.
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
let _cueCtx = null;
|
|
17
|
+
function getCueCtx() {
|
|
18
|
+
if (_cueCtx && _cueCtx.state !== 'closed') return _cueCtx;
|
|
19
|
+
try { _cueCtx = new (window.AudioContext || window.webkitAudioContext)(); } catch { return null; }
|
|
20
|
+
return _cueCtx;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function playCompletionCue() {
|
|
24
|
+
const ctx = getCueCtx();
|
|
25
|
+
if (!ctx) return;
|
|
26
|
+
const play = () => {
|
|
27
|
+
try {
|
|
28
|
+
const now = ctx.currentTime;
|
|
29
|
+
[523.25, 659.25].forEach((freq, i) => {
|
|
30
|
+
const osc = ctx.createOscillator();
|
|
31
|
+
const gain = ctx.createGain();
|
|
32
|
+
osc.connect(gain);
|
|
33
|
+
gain.connect(ctx.destination);
|
|
34
|
+
osc.type = 'sine';
|
|
35
|
+
osc.frequency.value = freq;
|
|
36
|
+
const t = now + i * 0.18;
|
|
37
|
+
gain.gain.setValueAtTime(0, t);
|
|
38
|
+
gain.gain.linearRampToValueAtTime(0.18, t + 0.02);
|
|
39
|
+
gain.gain.exponentialRampToValueAtTime(0.001, t + 0.45);
|
|
40
|
+
osc.start(t);
|
|
41
|
+
osc.stop(t + 0.45);
|
|
42
|
+
});
|
|
43
|
+
} catch { /* swallow: AudioContext/oscillator unsupported, cue is best-effort */ }
|
|
44
|
+
};
|
|
45
|
+
if (ctx.state === 'suspended') { ctx.resume().then(play).catch(() => {}); return; }
|
|
46
|
+
play();
|
|
47
|
+
}
|
|
48
|
+
|
|
8
49
|
function fmtDur(s) {
|
|
9
50
|
s = Math.max(0, Math.round(Number(s) || 0));
|
|
10
51
|
if (s < 60) return s + 's';
|
package/src/components.js
CHANGED
|
@@ -27,6 +27,8 @@ export {
|
|
|
27
27
|
|
|
28
28
|
export { AgentChat, MESSAGE_CAP } from './components/agent-chat.js';
|
|
29
29
|
|
|
30
|
+
export { ChatMinimap, CHAT_MINIMAP_WIDTH } from './components/chat-minimap.js';
|
|
31
|
+
|
|
30
32
|
export {
|
|
31
33
|
ConversationList, SessionCard, SessionDashboard, SessionMeta, fmtDuration, fmtTime, fmtAgo, AgentListSkeleton
|
|
32
34
|
} from './components/sessions.js';
|
|
@@ -39,6 +41,12 @@ export { GitStatusPanel, GitDiffView } from './components/git-status.js';
|
|
|
39
41
|
|
|
40
42
|
export { WorktreeSwitcher } from './components/worktree-switcher.js';
|
|
41
43
|
|
|
44
|
+
export { PluginsConfig } from './components/plugins-config.js';
|
|
45
|
+
|
|
46
|
+
export { SkillsConfig } from './components/skills-config.js';
|
|
47
|
+
|
|
48
|
+
export { ModelsConfig } from './components/models-config.js';
|
|
49
|
+
|
|
42
50
|
export {
|
|
43
51
|
DEFAULT_PHASES, PhaseWalk, TreeNode, BarRow, RateCell,
|
|
44
52
|
StatTile, StatsGrid, SubGrid, SessionRow, DevRow, LiveLogEntry, LiveLog
|
|
@@ -66,7 +74,8 @@ export {
|
|
|
66
74
|
} from './components/community.js';
|
|
67
75
|
|
|
68
76
|
export {
|
|
69
|
-
PttButton, VadMeter, WebcamPreview, VoiceSettingsModal, AudioQueue, VoiceControls
|
|
77
|
+
PttButton, VadMeter, WebcamPreview, VoiceSettingsModal, AudioQueue, VoiceControls,
|
|
78
|
+
playCompletionCue
|
|
70
79
|
} from './components/voice.js';
|
|
71
80
|
|
|
72
81
|
export { ThemeToggle } from './components/theme-toggle.js';
|
|
@@ -78,7 +87,8 @@ export {
|
|
|
78
87
|
export {
|
|
79
88
|
useDraggable, useDropTarget, useNumberScrub, usePointerDrag, Reorderable,
|
|
80
89
|
useKeyboardShortcut, formatShortcut, ShortcutHint, ShortcutList,
|
|
81
|
-
useKeyboardShortcutHelp, ShortcutHelpDialog
|
|
90
|
+
useKeyboardShortcutHelp, ShortcutHelpDialog,
|
|
91
|
+
isMobileNow, onMobileChange
|
|
82
92
|
} from './components/interaction-primitives.js';
|
|
83
93
|
|
|
84
94
|
export {
|
|
@@ -152,6 +152,31 @@
|
|
|
152
152
|
.chat-bubble.chat-md th { background: color-mix(in oklab, var(--fg) 5%, transparent); font-weight: 600; }
|
|
153
153
|
.chat-bubble.chat-md hr { border: 0; border-top: var(--bw-hair) solid var(--rule); margin: 12px 0; }
|
|
154
154
|
|
|
155
|
+
/* Mermaid diagram blocks — rendered SVG swapped in over the fenced source by
|
|
156
|
+
src/mermaid.js's renderMermaidBlocksUnder(); the source .pre stays in the
|
|
157
|
+
DOM (display:none) behind a source/diagram toggle button. */
|
|
158
|
+
.ds-mermaid-block {
|
|
159
|
+
position: relative; margin: var(--space-2) 0;
|
|
160
|
+
border: 1px solid color-mix(in oklab, var(--fg) 12%, transparent);
|
|
161
|
+
border-radius: var(--r-1); background: var(--bg); padding: 12px 16px;
|
|
162
|
+
}
|
|
163
|
+
.ds-mermaid-diagram { overflow-x: auto; display: flex; justify-content: center; }
|
|
164
|
+
.ds-mermaid-diagram svg { max-width: 100%; height: auto; }
|
|
165
|
+
.ds-mermaid-toggle {
|
|
166
|
+
position: absolute; top: 6px; right: 6px;
|
|
167
|
+
font: inherit; font-size: var(--fs-xs); line-height: 1;
|
|
168
|
+
background: color-mix(in oklab, var(--fg) 8%, transparent);
|
|
169
|
+
color: var(--fg); border: none; border-radius: var(--r-1);
|
|
170
|
+
padding: 4px 8px; cursor: pointer;
|
|
171
|
+
}
|
|
172
|
+
.ds-mermaid-toggle:hover { background: color-mix(in oklab, var(--fg) 14%, transparent); }
|
|
173
|
+
|
|
174
|
+
/* Inline/display math — KaTeX HTML swapped into text nodes by
|
|
175
|
+
src/math.js's renderMathBlocksUnder(). Display math centers on its own line;
|
|
176
|
+
inline math sits within running text. */
|
|
177
|
+
.ds-math-display { display: block; margin: var(--space-2) 0; text-align: center; overflow-x: auto; }
|
|
178
|
+
.ds-math-inline { display: inline-block; }
|
|
179
|
+
|
|
155
180
|
.chat-msg .chat-bubble.chat-code,
|
|
156
181
|
.chat-msg.you .chat-bubble.chat-code,
|
|
157
182
|
.chat-bubble.chat-code {
|
|
@@ -659,6 +659,24 @@
|
|
|
659
659
|
}
|
|
660
660
|
.ds-preview-text { white-space: pre-wrap; word-break: break-word; }
|
|
661
661
|
.ds-preview-code code, .ds-preview-text code { font: inherit; color: inherit; background: none; }
|
|
662
|
+
/* wrap-lines toggle (ported from pi-web's DisplayMode word-wrap control) */
|
|
663
|
+
.ds-preview-code.is-wrapped { white-space: pre-wrap; overflow-wrap: anywhere; }
|
|
664
|
+
.ds-preview-wrap-toggle.active { color: var(--paper); background: color-mix(in oklab, var(--paper) 18%, transparent); }
|
|
665
|
+
/* source/preview mode switch (ported from pi-web's markdown/HTML DisplayMode
|
|
666
|
+
tabs) — the host supplies already-rendered, already-sanitized HTML via
|
|
667
|
+
`previewHtml`; this component only toggles visibility. */
|
|
668
|
+
.ds-preview-mode-switch { display: inline-flex; gap: var(--space-1); margin-right: var(--space-1); }
|
|
669
|
+
.ds-preview-mode-btn {
|
|
670
|
+
font-family: var(--ff-mono); font-size: var(--fs-micro);
|
|
671
|
+
padding: var(--space-1) var(--space-2); border-radius: var(--r-1);
|
|
672
|
+
color: var(--paper-3); background: none; border: none; cursor: pointer;
|
|
673
|
+
}
|
|
674
|
+
.ds-preview-mode-btn.active { color: var(--paper); background: color-mix(in oklab, var(--paper) 18%, transparent); }
|
|
675
|
+
.ds-preview-html {
|
|
676
|
+
flex: 1; min-height: 0; overflow: auto;
|
|
677
|
+
padding: var(--space-3) var(--space-4);
|
|
678
|
+
background: var(--bg-0); border-radius: var(--r-2);
|
|
679
|
+
}
|
|
662
680
|
.ds-preview-truncated {
|
|
663
681
|
margin-top: var(--space-2); padding-top: var(--space-2);
|
|
664
682
|
border-top: var(--bw-hair) solid color-mix(in oklab, var(--paper) 20%, transparent);
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/* ============================================================
|
|
2
|
+
ModelsConfig — provider/model availability panel.
|
|
3
|
+
============================================================ */
|
|
4
|
+
.ds-mc { display: flex; flex-direction: column; gap: var(--space-3); }
|
|
5
|
+
|
|
6
|
+
.ds-mc-loading, .ds-mc-empty {
|
|
7
|
+
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
|
8
|
+
gap: var(--space-2); padding: var(--space-6) var(--space-3);
|
|
9
|
+
color: var(--fg-3); text-align: center;
|
|
10
|
+
}
|
|
11
|
+
.ds-mc-empty-hint { font-size: var(--fs-xs); color: var(--fg-3); }
|
|
12
|
+
|
|
13
|
+
/* Summary bar: totals + last-checked + refresh/rebuild actions. */
|
|
14
|
+
.ds-mc-summary {
|
|
15
|
+
display: flex; align-items: center; justify-content: space-between; gap: var(--space-3);
|
|
16
|
+
flex-wrap: wrap;
|
|
17
|
+
}
|
|
18
|
+
.ds-mc-summary-facts { display: flex; gap: var(--space-3); font-size: var(--fs-sm); color: var(--fg-2); }
|
|
19
|
+
.ds-mc-summary-ts { color: var(--fg-3); }
|
|
20
|
+
.ds-mc-summary-actions { display: flex; align-items: center; gap: var(--space-2); }
|
|
21
|
+
.ds-mc-rebuild-error { font-size: var(--fs-xs); color: var(--flame); }
|
|
22
|
+
|
|
23
|
+
/* Two-pane body: provider tree (left) + model detail (right). */
|
|
24
|
+
.ds-mc-body {
|
|
25
|
+
display: grid; grid-template-columns: minmax(220px, 300px) 1fr; gap: var(--space-3);
|
|
26
|
+
align-items: start;
|
|
27
|
+
}
|
|
28
|
+
@media (max-width: 720px) {
|
|
29
|
+
.ds-mc-body { grid-template-columns: 1fr; }
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.ds-mc-tree { display: flex; flex-direction: column; gap: 2px; }
|
|
33
|
+
.ds-mc-tree-group + .ds-mc-tree-group { margin-top: 2px; }
|
|
34
|
+
|
|
35
|
+
.ds-mc-key-chip {
|
|
36
|
+
font-family: var(--ff-mono); font-size: var(--fs-micro); font-weight: 700;
|
|
37
|
+
padding: 1px 6px; border-radius: var(--r-1);
|
|
38
|
+
}
|
|
39
|
+
.ds-mc-key-chip.tone-ok { color: var(--green-2); background: var(--green-tint); }
|
|
40
|
+
.ds-mc-key-chip.tone-fail { color: var(--fg-3); background: var(--bg-3); }
|
|
41
|
+
|
|
42
|
+
.ds-mc-sampler {
|
|
43
|
+
display: inline-block; margin: 2px 0 4px 12px;
|
|
44
|
+
font-size: var(--fs-micro); padding: 1px 6px; border-radius: var(--r-1);
|
|
45
|
+
}
|
|
46
|
+
.ds-mc-sampler.tone-ok { color: var(--green-2); background: var(--green-tint); }
|
|
47
|
+
.ds-mc-sampler.tone-fail { color: var(--ink); background: var(--sun); }
|
|
48
|
+
|
|
49
|
+
/* Detail pane */
|
|
50
|
+
.ds-mc-detail-empty { padding: var(--space-3); color: var(--fg-3); font-size: var(--fs-sm); }
|
|
51
|
+
.ds-mc-detail-head {
|
|
52
|
+
display: flex; align-items: center; gap: var(--space-2);
|
|
53
|
+
margin-bottom: var(--space-2);
|
|
54
|
+
}
|
|
55
|
+
.ds-mc-detail-title { font-family: var(--ff-mono); font-size: var(--fs-base); font-weight: 700; }
|
|
56
|
+
|
|
57
|
+
.ds-mc-discovery-error {
|
|
58
|
+
display: flex; align-items: center; gap: var(--space-1-75);
|
|
59
|
+
padding: var(--space-1-75) var(--space-2);
|
|
60
|
+
margin-bottom: var(--space-2);
|
|
61
|
+
color: var(--flame); background: color-mix(in oklab, var(--flame) 12%, transparent);
|
|
62
|
+
border-radius: var(--r-1); font-size: var(--fs-xs);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.ds-mc-model-list { display: flex; flex-direction: column; gap: var(--space-2); }
|
|
66
|
+
.ds-mc-model-row {
|
|
67
|
+
padding: var(--space-2); border: var(--bw-hair) solid var(--rule); border-radius: var(--r-2);
|
|
68
|
+
}
|
|
69
|
+
.ds-mc-model-row.active { border-color: var(--accent); background: var(--accent-tint); }
|
|
70
|
+
.ds-mc-model-head {
|
|
71
|
+
display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap;
|
|
72
|
+
margin-bottom: var(--space-1-75);
|
|
73
|
+
}
|
|
74
|
+
.ds-mc-model-id { font-family: var(--ff-mono); font-size: var(--fs-sm); font-weight: 600; }
|
|
75
|
+
.ds-mc-model-via { font-size: var(--fs-micro); color: var(--fg-3); }
|
|
76
|
+
.ds-mc-usable-chip {
|
|
77
|
+
font-size: var(--fs-micro); font-weight: 700; padding: 1px 6px; border-radius: var(--r-1);
|
|
78
|
+
margin-left: auto;
|
|
79
|
+
}
|
|
80
|
+
.ds-mc-usable-chip.tone-ok { color: var(--green-2); background: var(--green-tint); }
|
|
81
|
+
.ds-mc-usable-chip.tone-fail { color: var(--fg-3); background: var(--bg-3); }
|
|
82
|
+
|
|
83
|
+
/* 7-mode availability grid — one chip per mode, wraps on narrow panes. */
|
|
84
|
+
.ds-mc-mode-grid { display: flex; flex-wrap: wrap; gap: 4px; }
|
|
85
|
+
.ds-mc-chip {
|
|
86
|
+
font-family: var(--ff-mono); font-size: var(--fs-micro); font-weight: 600;
|
|
87
|
+
padding: 2px 7px; border-radius: var(--r-1);
|
|
88
|
+
border: var(--bw-hair) solid transparent;
|
|
89
|
+
}
|
|
90
|
+
.ds-mc-chip.tone-ok { color: var(--green-2); background: var(--green-tint); }
|
|
91
|
+
.ds-mc-chip.tone-fail { color: var(--on-color); background: var(--flame); }
|
|
92
|
+
.ds-mc-chip.tone-skip { color: var(--fg-3); background: var(--bg-3); }
|
|
93
|
+
.ds-mc-chip.tone-unknown { color: var(--fg-3); background: none; border-color: var(--rule); opacity: 0.6; }
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/* ============================================================
|
|
2
|
+
PluginsConfig — plugin/extension list + detail modal.
|
|
3
|
+
============================================================ */
|
|
4
|
+
|
|
5
|
+
.ds-plugins-overlay {
|
|
6
|
+
position: fixed; inset: 0; z-index: var(--z-modal, 1000);
|
|
7
|
+
background: color-mix(in oklab, var(--ink) 35%, transparent);
|
|
8
|
+
display: flex; align-items: center; justify-content: center;
|
|
9
|
+
padding: var(--space-3);
|
|
10
|
+
}
|
|
11
|
+
.ds-plugins-modal {
|
|
12
|
+
width: min(860px, 100%); height: min(76vh, 720px);
|
|
13
|
+
background: var(--bg); border: var(--bw-hair) solid var(--rule); border-radius: var(--r-3);
|
|
14
|
+
display: flex; flex-direction: column; overflow: hidden;
|
|
15
|
+
box-shadow: var(--shadow-3, 0 8px 32px rgba(0,0,0,0.18));
|
|
16
|
+
}
|
|
17
|
+
.ds-plugins-header {
|
|
18
|
+
display: flex; align-items: center; justify-content: space-between;
|
|
19
|
+
padding: var(--space-3) var(--space-4);
|
|
20
|
+
border-bottom: var(--bw-hair) solid var(--rule); flex: 0 0 auto;
|
|
21
|
+
}
|
|
22
|
+
.ds-plugins-title { font-size: var(--fs-md); font-weight: 700; color: var(--fg); }
|
|
23
|
+
.ds-plugins-close {
|
|
24
|
+
background: none; border: none; color: var(--fg-3); cursor: pointer;
|
|
25
|
+
font-size: 20px; line-height: 1; padding: 2px 6px; border-radius: var(--r-1);
|
|
26
|
+
}
|
|
27
|
+
.ds-plugins-close:hover { background: var(--bg-2); color: var(--fg); }
|
|
28
|
+
.ds-plugins-close:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
|
|
29
|
+
|
|
30
|
+
.ds-plugins-body { flex: 1 1 auto; display: flex; overflow: hidden; }
|
|
31
|
+
|
|
32
|
+
.ds-plugins-sidebar {
|
|
33
|
+
width: 245px; flex: 0 0 auto; overflow-y: auto;
|
|
34
|
+
border-right: var(--bw-hair) solid var(--rule); background: var(--bg-2);
|
|
35
|
+
padding: var(--space-2);
|
|
36
|
+
}
|
|
37
|
+
.ds-plugins-sidebar-status {
|
|
38
|
+
padding: var(--space-3) var(--space-2); font-size: var(--fs-sm); color: var(--fg-3);
|
|
39
|
+
}
|
|
40
|
+
.ds-plugins-sidebar-status.ds-plugins-status-error { color: var(--flame); }
|
|
41
|
+
.ds-plugins-list { display: flex; flex-direction: column; gap: 2px; }
|
|
42
|
+
|
|
43
|
+
.ds-plugins-row {
|
|
44
|
+
display: flex; align-items: center; gap: 8px; width: 100%;
|
|
45
|
+
padding: var(--space-2); border-radius: var(--r-2);
|
|
46
|
+
background: none; border: var(--bw-hair) solid transparent; text-align: left; cursor: pointer;
|
|
47
|
+
color: var(--fg); font: inherit;
|
|
48
|
+
transition: background var(--dur-snap) var(--ease), border-color var(--dur-snap) var(--ease);
|
|
49
|
+
}
|
|
50
|
+
.ds-plugins-row:hover { background: var(--bg-3, var(--bg)); }
|
|
51
|
+
.ds-plugins-row.active { background: var(--accent-tint); border-color: var(--accent); }
|
|
52
|
+
.ds-plugins-row:focus-visible { outline: var(--focus-w) solid var(--focus-color); outline-offset: var(--focus-offset); }
|
|
53
|
+
|
|
54
|
+
.ds-plugins-row-body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
|
|
55
|
+
.ds-plugins-row-name {
|
|
56
|
+
font-family: var(--ff-mono); font-size: var(--fs-sm); color: var(--fg);
|
|
57
|
+
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
58
|
+
}
|
|
59
|
+
.ds-plugins-row-meta {
|
|
60
|
+
font-size: var(--fs-micro); color: var(--fg-3);
|
|
61
|
+
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
62
|
+
}
|
|
63
|
+
.ds-plugins-row-busy { flex: 0 0 auto; font-size: var(--fs-micro); color: var(--fg-3); }
|
|
64
|
+
|
|
65
|
+
.ds-plugins-dot {
|
|
66
|
+
flex: 0 0 auto; width: 7px; height: 7px; border-radius: 50%;
|
|
67
|
+
}
|
|
68
|
+
.ds-plugins-dot.tone-add { background: var(--green-2); }
|
|
69
|
+
.ds-plugins-dot.tone-delete { background: var(--flame); }
|
|
70
|
+
.ds-plugins-dot.tone-neutral { background: var(--fg-3); }
|
|
71
|
+
|
|
72
|
+
.ds-plugins-main { flex: 1 1 auto; overflow-y: auto; padding: var(--space-4); }
|
|
73
|
+
|
|
74
|
+
.ds-plugins-empty {
|
|
75
|
+
height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center;
|
|
76
|
+
gap: var(--space-2); color: var(--fg-3);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.ds-plugins-detail { display: flex; flex-direction: column; gap: var(--space-4); max-width: 640px; }
|
|
80
|
+
.ds-plugins-detail-head {
|
|
81
|
+
display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); flex-wrap: wrap;
|
|
82
|
+
}
|
|
83
|
+
.ds-plugins-detail-title { display: flex; align-items: center; gap: 8px; min-width: 0; }
|
|
84
|
+
.ds-plugins-detail-title .name {
|
|
85
|
+
font-family: var(--ff-mono); font-size: var(--fs-md); font-weight: 600; color: var(--fg);
|
|
86
|
+
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
87
|
+
}
|
|
88
|
+
.ds-plugins-version { font-size: var(--fs-micro); color: var(--fg-3); }
|
|
89
|
+
|
|
90
|
+
.ds-plugins-toggle {
|
|
91
|
+
flex: 0 0 auto; width: 40px; height: 22px; border-radius: 11px; border: none; padding: 0;
|
|
92
|
+
background: var(--rule); position: relative; cursor: pointer;
|
|
93
|
+
transition: background var(--dur-snap) var(--ease);
|
|
94
|
+
}
|
|
95
|
+
.ds-plugins-toggle.on { background: var(--accent); }
|
|
96
|
+
.ds-plugins-toggle[disabled] { cursor: wait; opacity: 0.65; }
|
|
97
|
+
.ds-plugins-toggle-knob {
|
|
98
|
+
position: absolute; top: 3px; left: 3px; width: 16px; height: 16px; border-radius: 50%;
|
|
99
|
+
background: var(--bg); box-shadow: var(--shadow-1, 0 1px 4px rgba(0,0,0,0.22));
|
|
100
|
+
transition: left var(--dur-snap) var(--ease);
|
|
101
|
+
}
|
|
102
|
+
.ds-plugins-toggle.on .ds-plugins-toggle-knob { left: 21px; }
|
|
103
|
+
|
|
104
|
+
.ds-plugins-fact-grid {
|
|
105
|
+
display: grid; grid-template-columns: minmax(96px, 130px) minmax(0, 1fr);
|
|
106
|
+
gap: 9px var(--space-3); font-size: var(--fs-sm);
|
|
107
|
+
}
|
|
108
|
+
.ds-plugins-fact-label { color: var(--fg-3); }
|
|
109
|
+
.ds-plugins-fact-value { color: var(--fg-2); }
|
|
110
|
+
.ds-plugins-fact-value.ds-plugins-mono { font-family: var(--ff-mono); overflow-wrap: anywhere; }
|
|
111
|
+
.ds-plugins-fact-value.tone-text-add { color: var(--green-2); }
|
|
112
|
+
.ds-plugins-fact-value.tone-text-delete { color: var(--flame); }
|
|
113
|
+
.ds-plugins-fact-value.tone-text-neutral { color: var(--fg-3); }
|
|
114
|
+
|
|
115
|
+
.ds-plugins-group-label {
|
|
116
|
+
font-size: var(--fs-micro); font-weight: 600; color: var(--fg-3);
|
|
117
|
+
text-transform: uppercase; letter-spacing: 0.02em; margin-bottom: 6px;
|
|
118
|
+
}
|
|
119
|
+
.ds-plugins-requires-list { display: flex; flex-wrap: wrap; gap: 6px; }
|
|
120
|
+
.ds-plugins-chip {
|
|
121
|
+
font-family: var(--ff-mono); font-size: var(--fs-micro); color: var(--fg-2);
|
|
122
|
+
border: var(--bw-hair) solid var(--rule); border-radius: var(--r-1); padding: 2px 7px;
|
|
123
|
+
}
|
|
124
|
+
.ds-plugins-requires-empty { font-size: var(--fs-sm); color: var(--fg-3); }
|
|
125
|
+
|
|
126
|
+
.ds-plugins-detail-actions { display: flex; gap: var(--space-2); }
|
|
127
|
+
.ds-plugins-btn {
|
|
128
|
+
padding: 6px 12px; background: none; border: var(--bw-hair) solid var(--rule); border-radius: var(--r-2);
|
|
129
|
+
color: var(--fg-2); cursor: pointer; font-size: var(--fs-sm);
|
|
130
|
+
}
|
|
131
|
+
.ds-plugins-btn:hover { background: var(--bg-2); }
|
|
132
|
+
.ds-plugins-btn[disabled] { cursor: not-allowed; opacity: 0.5; }
|
|
133
|
+
|
|
134
|
+
.ds-plugins-footer {
|
|
135
|
+
display: flex; align-items: center; justify-content: flex-end;
|
|
136
|
+
padding: var(--space-2) var(--space-4);
|
|
137
|
+
border-top: var(--bw-hair) solid var(--rule); flex: 0 0 auto;
|
|
138
|
+
}
|
|
139
|
+
.ds-plugins-footer-count { font-size: var(--fs-micro); color: var(--fg-3); }
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/* ============================================================
|
|
2
|
+
SkillsConfig — skill list + detail panel. Shares chrome with
|
|
3
|
+
PluginsConfig (.ds-plugins-overlay/-modal/-header/-body/-sidebar/-list/
|
|
4
|
+
-row/-dot/-main/-detail/-toggle/-fact-grid/-chip/-footer); the classes
|
|
5
|
+
below are the skills-specific additions only.
|
|
6
|
+
============================================================ */
|
|
7
|
+
|
|
8
|
+
.ds-skills-search-row {
|
|
9
|
+
padding: var(--space-2) var(--space-4);
|
|
10
|
+
border-bottom: var(--bw-hair) solid var(--rule); flex: 0 0 auto;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.ds-skills-group { margin-bottom: var(--space-2); }
|
|
14
|
+
.ds-skills-group-label {
|
|
15
|
+
padding: var(--space-2) var(--space-2) 3px;
|
|
16
|
+
font-size: var(--fs-micro); font-weight: 600; color: var(--fg-3);
|
|
17
|
+
text-transform: uppercase; letter-spacing: 0.06em;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.ds-skills-description { font-size: var(--fs-sm); color: var(--fg-2); line-height: 1.5; }
|
|
21
|
+
|
|
22
|
+
.ds-skills-body-group { display: flex; flex-direction: column; }
|
|
23
|
+
.ds-skills-body-preview {
|
|
24
|
+
font-family: var(--ff-mono); font-size: var(--fs-micro); color: var(--fg-2);
|
|
25
|
+
background: var(--bg-2); border: var(--bw-hair) solid var(--rule); border-radius: var(--r-2);
|
|
26
|
+
padding: var(--space-3); overflow: auto; max-height: 260px; white-space: pre-wrap; word-break: break-word;
|
|
27
|
+
}
|