feat(ui): AI Tools modal, one-button lane tool picker, AgentHub settings in Overview, markdown preview

- AI Tools moves from a Settings section into a modal behind a button at the
  Settings tab bar's right edge (AiToolsModal, `actions` on PageTabs,
  /settings#ai-tools); rows get an enable switch, Default badge, and an
  Update button for every tool whose catalog names an updater (no version
  lookup on open); not-installed tools fold behind a disclosure, a finished
  job's log folds to one line; shared AiToolIcon
- codex updates through its own `codex update`, openclaw/hermes gain
  `update --yes`; update-all runs every installed updater and skips an npm
  one only when npm does not manage the binary
- Add-lane tool picker is one button showing the chosen tool that opens the
  enabled tools as buttons
- Claude Code / Codex AgentHub sub-tab folded into Overview (home editor,
  hooks, pricing); the path list drops CLAUDE_HOME/CODEX_HOME;
  HomeDirSetting shows the saved value only while the field differs
- Preview/Raw toggle for markdown files in the config FileViewer and the
  Changes panel's whole-file view (MarkdownPreview: react-markdown +
  remark-gfm, raw HTML never run, frontmatter as a code block)
- docs and the CLAUDE.md marker updated
This commit is contained in:
2026-10-01 10:11:43 +07:00
parent 058c574138
commit c5aba094bd
55 changed files with 2985 additions and 853 deletions
+139
View File
@@ -441,3 +441,142 @@
.animate-pulse-dot {
animation: pulse-dot 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
/* Rendered markdown (MarkdownPreview.tsx): theme tokens only, so every theme
reads it; no typography plugin. */
.md-preview {
color: rgb(var(--fg-secondary));
font-size: 13px;
line-height: 1.6;
overflow-wrap: anywhere;
}
.md-preview > :first-child {
margin-top: 0;
}
.md-preview h1,
.md-preview h2,
.md-preview h3,
.md-preview h4,
.md-preview h5,
.md-preview h6 {
color: rgb(var(--fg-primary));
font-weight: 600;
line-height: 1.3;
margin: 1.4em 0 0.6em;
}
.md-preview h1 {
font-size: 1.6em;
padding-bottom: 0.3em;
border-bottom: 1px solid rgb(var(--border));
}
.md-preview h2 {
font-size: 1.3em;
padding-bottom: 0.25em;
border-bottom: 1px solid rgb(var(--border));
}
.md-preview h3 {
font-size: 1.12em;
}
.md-preview h4,
.md-preview h5,
.md-preview h6 {
font-size: 1em;
}
.md-preview p,
.md-preview ul,
.md-preview ol,
.md-preview blockquote,
.md-preview pre,
.md-preview table {
margin: 0 0 0.9em;
}
.md-preview ul {
list-style: disc;
padding-left: 1.5em;
}
.md-preview ol {
list-style: decimal;
padding-left: 1.5em;
}
.md-preview li + li {
margin-top: 0.2em;
}
.md-preview li > ul,
.md-preview li > ol {
margin: 0.2em 0 0;
}
.md-preview li.task-list-item {
list-style: none;
margin-left: -1.3em;
}
.md-preview li.task-list-item input {
margin-right: 0.4em;
vertical-align: middle;
}
.md-preview a {
color: rgb(var(--accent));
text-decoration: underline;
text-underline-offset: 2px;
}
.md-preview strong {
color: rgb(var(--fg-primary));
font-weight: 600;
}
.md-preview code {
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
font-size: 0.88em;
padding: 0.1em 0.35em;
border-radius: 4px;
background: rgb(var(--surface-3));
color: rgb(var(--fg-primary));
}
.md-preview pre,
.md-preview .md-frontmatter {
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
font-size: 12px;
line-height: 1.5;
padding: 0.75em 1em;
border-radius: 6px;
border: 1px solid rgb(var(--border));
background: rgb(var(--surface-0));
overflow-x: auto;
white-space: pre;
}
.md-preview .md-frontmatter {
margin: 0 0 1em;
color: rgb(var(--fg-muted));
}
.md-preview pre code {
padding: 0;
background: none;
font-size: inherit;
}
.md-preview blockquote {
padding: 0 1em;
border-left: 3px solid rgb(var(--border));
color: rgb(var(--fg-muted));
}
.md-preview hr {
margin: 1.5em 0;
border: 0;
border-top: 1px solid rgb(var(--border));
}
.md-preview table {
display: block;
max-width: 100%;
overflow-x: auto;
border-collapse: collapse;
}
.md-preview th,
.md-preview td {
padding: 0.35em 0.75em;
border: 1px solid rgb(var(--border));
}
.md-preview th {
color: rgb(var(--fg-primary));
font-weight: 600;
background: rgb(var(--surface-2));
}
.md-preview img {
max-width: 100%;
}