Merge branch 'stack/agent-profiles-5-web-ui' into stack/agent-profiles-8-authoring
# Conflicts: # apps/cli/tests/web-agent-presets.e2e.ts # packages/client/connection/README.i18n.yaml # packages/client/connection/README.md # packages/client/connection/README.zh.md # packages/client/ui-conversation/src/client/contract/slots.ts # packages/client/ui-primitives/tests/icons.spec.tsx # packages/client/ui-settings/src/client/contract/slots.ts # packages/host/apiproxy/tests/api-proxy-agent-preset.spec.ts
This commit is contained in:
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write packages/client/ui-primitives/README.md
|
||||
README.md: 098a202a4ac9ee263ce1beaaee7a8624ebf26b80
|
||||
README.zh.md: def1907f81d06b5afdf19af5f19ba17a269ed3c1
|
||||
README.md: a9c802c1e43cf06aa0492b39d5052e882a72d9e6
|
||||
README.zh.md: 9e67488ccc1d70263bd0b91d167c4c251ee95926
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
English | [中文](README.zh.md)
|
||||
|
||||
Pure React atoms (zero cordis): StateDot, DisclosureRow, ic_ds_* icons, Button/Pill/Menu/Modal/Input, the OnboardingSurface first-run takeover (body-portaled mask + opaque stage that holds `#root` inert for exactly its own lifetime), the markdown family (MessageText/MarkdownText/JsonBlock), the read-only JsonTree inspector, the `useAnchoredMaxHeight` hook that clamps a bottom-anchored overlay to the viewport space above its anchor (re-measured on resize, scroll, and a caller-supplied dependency), TerminalBlock, DiffBlock, ReadBlock, SearchBlock, and WebBlock. Contract: api-contracts v3 §8.
|
||||
Pure React atoms (zero cordis): StateDot, DisclosureRow, ic_ds_* icons, Button/Pill/Menu/Modal/Input, the OnboardingSurface first-run takeover (body-portaled mask + opaque stage that holds `#root` inert for exactly its own lifetime), the markdown family (MessageText/MarkdownText/JsonBlock), the read-only JsonTree inspector, the `useAnchoredMaxHeight` hook that clamps a bottom-anchored overlay to the viewport space above its anchor (re-measured on resize, scroll, and a caller-supplied dependency), TerminalBlock, DiffBlock, ReadBlock, SearchBlock, and WebBlock.
|
||||
|
||||
## Hover cards
|
||||
|
||||
@@ -46,5 +46,5 @@ None; this package neither assembles nor sends a provider request.
|
||||
- **Glyph-level icons are redrawn approximations** — the fish logo (and the sparkle held by ui-conversation) come from font glyphs whose vector geometry is not exportable from the local design data; hand-authored recreations stand in until an exact export path exists.
|
||||
- **Pill and Input have no design source** — both atoms are self-defined; the sidebar search field and view-tab strip that resemble them are consumer-owned compositions, not these atoms.
|
||||
- **No `Active` StateDot variant** — the supported states are done, warning, ongoing, and error.
|
||||
- **User-facing copy localizes through label props, defaulting to the original Chinese literals** — the atoms are zero-cordis and cannot reach `ctx.locale`, so `HoverCard` (`copyLabel`/`copiedLabel`), `TerminalBlock` (`labels`), `JsonTree` (`labels`), `CodeBlock` (`copyLabel`/`copiedLabel`), `MarkdownText` (`codeLabels`), `JsonBlock` (`truncatedLabel`), `ConnectionBanner` (`label`), and `Modal` (`closeLabel`) take their copy as optional props with the previous hardcoded strings as defaults. Localized plugins pass dictionary-driven labels from their own `t` seat; a consumer that passes nothing renders exactly the pre-localization output. `WebBlock` does not yet follow this pattern: its source-list and fetch truncation notes and its empty-search note stay inline Chinese, pending the same label-prop treatment.
|
||||
- **User-facing copy localizes through label props, defaulting to the original Chinese literals** — the atoms are zero-cordis and cannot reach `ctx.locale`, so `HoverCard` (`copyLabel`/`copiedLabel`), `TerminalBlock` (`labels`), `JsonTree` (`labels`), `CodeBlock` (`copyLabel`/`copiedLabel`), `MarkdownText` (`codeLabels`), `JsonBlock` (`truncatedLabel`), `ConnectionBanner` (`label`), and `Modal` (`closeLabel`) take their copy as optional props. Localized plugins pass dictionary-driven labels from their own `t` seat; a consumer that passes nothing gets those defaults. `WebBlock` does not yet follow this pattern: its source-list and fetch truncation notes and its empty-search note stay inline Chinese, pending the same label-prop treatment.
|
||||
- **`TerminalBlock` is not a terminal emulator** — it renders settled or still-running command output, not an interactive session: SGR color and attributes are honored, and so are the in-line cursor movements a progress line uses — carriage return, backspace, erase-in-line, tab stops and character width. Absolute cursor positioning, screen clearing, and alternate-screen sequences are stripped. Basic-16 magenta and cyan have no token equivalent and stay literal rgb.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
[English](README.md) | 中文
|
||||
|
||||
纯 React 原子组件(零 cordis):StateDot、DisclosureRow、ic_ds_* 图标、Button/Pill/Menu/Modal/Input、OnboardingSurface 首次使用接管层(portal 到 body 的遮罩加不透明展示层,在且仅在自身生命周期内保持 `#root` 为 `inert`)、markdown 家族(MessageText/MarkdownText/JsonBlock)、只读 JsonTree 检查器、`useAnchoredMaxHeight` 钩子(把底部锚定的浮层高度收敛到锚点上方的视口空间,并在 resize、scroll 与调用方提供的依赖变化时重新测量)、TerminalBlock、DiffBlock、ReadBlock、SearchBlock,以及 WebBlock。约定:api-contracts v3 §8。
|
||||
纯 React 原子组件(零 cordis):StateDot、DisclosureRow、ic_ds_* 图标、Button/Pill/Menu/Modal/Input、OnboardingSurface 首次使用接管层(portal 到 body 的遮罩加不透明展示层,在且仅在自身生命周期内保持 `#root` 为 `inert`)、markdown 家族(MessageText/MarkdownText/JsonBlock)、只读 JsonTree 检查器、`useAnchoredMaxHeight` 钩子(把底部锚定的浮层高度收敛到锚点上方的视口空间,并在 resize、scroll 与调用方提供的依赖变化时重新测量)、TerminalBlock、DiffBlock、ReadBlock、SearchBlock,以及 WebBlock。
|
||||
|
||||
## 悬浮卡片
|
||||
|
||||
@@ -46,5 +46,5 @@
|
||||
- **字形级图标是重新绘制的近似版本**:鱼形标志(以及 ui-conversation 持有的闪光图标)来自字体字形,而本地设计数据无法导出其矢量几何;在获得精确导出路径前,使用手工重建版本代替。
|
||||
- **Pill 与 Input 没有设计来源**:两个原子组件均自行定义;与其相似的侧边栏搜索字段和视图标签条由消费方组合,不是这些原子组件。
|
||||
- **StateDot 没有 `Active` 变体**:支持的状态为 done、warning、ongoing 和 error。
|
||||
- **面向用户的文案经 label props 本地化,默认值为原中文字面量**:这些原子组件是 zero-cordis 的,拿不到 `ctx.locale`,因此 `HoverCard`(`copyLabel`/`copiedLabel`)、`TerminalBlock`(`labels`)、`JsonTree`(`labels`)、`CodeBlock`(`copyLabel`/`copiedLabel`)、`MarkdownText`(`codeLabels`)、`JsonBlock`(`truncatedLabel`)、`ConnectionBanner`(`label`)和 `Modal`(`closeLabel`)都把文案作为可选 props 接收,默认值即此前的硬编码字符串。已本地化的插件用自己的 `t` 席位传入字典驱动的 label;什么都不传的消费者渲染与本地化之前逐字节一致。`WebBlock` 尚未跟进这一模式:它的来源列表截断提示与 fetch 截断提示、以及空搜索提示仍是内联中文,待同样的 label-prop 处理。
|
||||
- **面向用户的文案经 label props 本地化,默认值为原中文字面量**:这些原子组件是 zero-cordis 的,拿不到 `ctx.locale`,因此 `HoverCard`(`copyLabel`/`copiedLabel`)、`TerminalBlock`(`labels`)、`JsonTree`(`labels`)、`CodeBlock`(`copyLabel`/`copiedLabel`)、`MarkdownText`(`codeLabels`)、`JsonBlock`(`truncatedLabel`)、`ConnectionBanner`(`label`)和 `Modal`(`closeLabel`)都把文案作为可选 props 接收。已本地化的插件用自己的 `t` 席位传入字典驱动的 label;什么都不传的消费方得到的就是这些默认值。`WebBlock` 尚未跟进这一模式:它的来源列表截断提示与 fetch 截断提示、以及空搜索提示仍是内联中文,待同样的 label-prop 处理。
|
||||
- **`TerminalBlock` 不是终端模拟器**:它渲染已结束或仍在运行的命令输出,而不是交互式会话:SGR 颜色与属性会被遵循,进度行所用的行内光标移动同样被遵循——回车、退格、行内擦除、制表位与字符宽度。绝对光标定位、清屏与备用屏幕序列会被剥离。基础 16 色中的洋红与青色没有对应 token,保持字面 rgb。
|
||||
|
||||
@@ -221,8 +221,8 @@ export function TerminalBlock({
|
||||
// Read from the parsed lines the card actually renders, not from the raw text:
|
||||
// output that is only escapes or control bytes (a lone reset, an OSC title, an
|
||||
// erase) survives `text.trim()` yet parses to nothing visible. Judging it on
|
||||
// the raw text drew an output box of blank rows plus a copy control for
|
||||
// invisible bytes, and hid the placeholder that belongs there.
|
||||
// the raw text would draw an output box of blank rows plus a copy control
|
||||
// for invisible bytes, and hide the placeholder that belongs there.
|
||||
const empty = lines.every(line => line.every(span => span.text.trim() === ''))
|
||||
const { hidden, capped, headLines, tailLines } = headTailCap(lines.length, maxLines, expanded)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Visual spec mirrors deepsuite @deepseek/ui Tooltip.css (size m, no arrow),
|
||||
except padding tightened 6/12 -> 3/7, type 14/22 -> 13/20, and radius
|
||||
10 -> 8 by product ruling: tooltip-bg plate,
|
||||
except padding tightened 6/12 -> 3/7, type 14/22 -> 13/20, radius
|
||||
10 -> 8, a tooltip-bg plate,
|
||||
one text color across both themes (the plate stays dark in light and dark
|
||||
mode). Behavior (fixed positioning off the anchor rect) is local — the
|
||||
upstream Floating stack is intentionally not vendored. */
|
||||
|
||||
@@ -84,8 +84,7 @@ const LAZY_GRAMMARS = new Map<string, () => Promise<LangModule>>([
|
||||
* the markdown-fence aliases `CodeBlock` uses and the file-extension hint ids
|
||||
* the read tool's `langFromPath` emits, so both callers resolve the same
|
||||
* grammars. The JS family maps to the TypeScript grammar (see {@link LANGS} for
|
||||
* the JSX/TSX approximation), unchanged from when this was the only
|
||||
* non-shell/JSON grammar. A value not in {@link LANGS} names a
|
||||
* the JSX/TSX approximation). A value not in {@link LANGS} names a
|
||||
* {@link LAZY_GRAMMARS} entry loaded on first use.
|
||||
*/
|
||||
const LANG_ALIASES = new Map<string, string>([
|
||||
|
||||
@@ -359,10 +359,10 @@ describe('parseAnsiLines: line-end state and column widths', () => {
|
||||
|
||||
describe('parseAnsiLines: bounded state and true widths', () => {
|
||||
it('emits one canonical sequence per boundary however the state was reached', () => {
|
||||
// Colors that never fully reset used to accumulate raw sequence history per
|
||||
// cell, so every boundary re-emitted the whole chain: 3200 such cells
|
||||
// produced 25 MB and eventually a RangeError. The state is normalized now,
|
||||
// so the emitted text stays linear in the number of cells.
|
||||
// Colors that never fully reset would, under a raw per-cell sequence
|
||||
// history, re-emit the whole chain at every boundary: 3200 such cells
|
||||
// produce 25 MB and eventually a RangeError. Normalized state keeps
|
||||
// the emitted text linear in the number of cells.
|
||||
let input = ''
|
||||
for (let index = 0; index < 2000; index += 1) input += `${ESC}[3${index % 6 + 1}mx`
|
||||
const emitted = parseAnsiLines(`${input}\rz`)[0] ?? []
|
||||
|
||||
@@ -91,8 +91,8 @@ describe('HoverCard', () => {
|
||||
|
||||
it('reaching the card inside the grace keeps it open without restarting the dwell', () => {
|
||||
// The portaled card is a React child of the wrapper, so the pointer
|
||||
// arriving on it re-enters the wrapper — the gesture the 8px anchor gap
|
||||
// used to make impossible.
|
||||
// arriving on it re-enters the wrapper — the gesture an anchor gap
|
||||
// would make impossible.
|
||||
const { wrapper } = mount()
|
||||
fireEvent.pointerEnter(wrapper)
|
||||
act(() => { vi.advanceTimersByTime(500) })
|
||||
|
||||
@@ -16,7 +16,7 @@ const icons = Object.fromEntries(
|
||||
const iconNames = Object.keys(icons)
|
||||
|
||||
describe('ic_ds_ icon set', () => {
|
||||
it('exports the full P-I set (46 deepsuite + 18 figma extracts + three product glyphs outside those sets)', () => {
|
||||
it('exports the full icon set (46 deepsuite + 18 figma extracts + three product glyphs outside those sets)', () => {
|
||||
expect(iconNames.length).toBe(67)
|
||||
})
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { clientOnly } from '../tsdown.client.ts'
|
||||
|
||||
/**
|
||||
* ui-primitives is browser-only, but its lib bundle IS imported under plain
|
||||
* Node now that the web shell is a lib (dsh-client-web's lib chain reaches
|
||||
* Node because the web shell is a lib (dsh-client-web's lib chain reaches
|
||||
* this package). CSS imports are therefore stubbed to empty modules instead
|
||||
* of externalized — the hashed class maps only matter in bundler contexts
|
||||
* (loader module table / vite source paths), which compile src directly and
|
||||
|
||||
Reference in New Issue
Block a user