fmt(js): npm run fix on merge (#86801)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
0930133dbf
commit
af585de28e
@@ -116,6 +116,7 @@ test('merge preserves fields the editor does not carry (org, ssh extras)', () =>
|
||||
org: 'nous',
|
||||
url: 'https://a.cloud'
|
||||
}
|
||||
|
||||
const renamed = mergeConnectionInput({ id: 'c', kind: 'cloud', label: 'Renamed', url: 'https://a.cloud' }, cloud)
|
||||
|
||||
assert.equal(renamed.org, 'nous')
|
||||
|
||||
@@ -44,10 +44,7 @@ test('keeps URL-dependent image actions when srcURL is available', () => {
|
||||
const { actions, calls } = createActions()
|
||||
const url = 'https://example.com/image.png'
|
||||
|
||||
const items = imageContextMenuItems(
|
||||
{ mediaType: 'image', hasImageContents: true, srcURL: url, x: 5, y: 8 },
|
||||
actions
|
||||
)
|
||||
const items = imageContextMenuItems({ mediaType: 'image', hasImageContents: true, srcURL: url, x: 5, y: 8 }, actions)
|
||||
|
||||
assert.deepEqual(
|
||||
items.map(item => item.label),
|
||||
|
||||
@@ -4677,6 +4677,7 @@ function downloadViaTokenToFile(url, token, ctx, options: any = {}) {
|
||||
|
||||
const client = parsed.protocol === 'https:' ? https : http
|
||||
const timeoutMs = resolveTimeoutMs(options.timeoutMs, DEFAULT_FETCH_TIMEOUT_MS)
|
||||
|
||||
const req = client.request(
|
||||
parsed,
|
||||
{
|
||||
@@ -6838,6 +6839,7 @@ function downloadViaOauthSessionToFile(url, ctx, options: any = {}) {
|
||||
}
|
||||
|
||||
const timeoutMs = resolveTimeoutMs(options.timeoutMs, DEFAULT_FETCH_TIMEOUT_MS)
|
||||
|
||||
const request = electronNet.request({
|
||||
method: 'GET',
|
||||
url,
|
||||
@@ -6845,6 +6847,7 @@ function downloadViaOauthSessionToFile(url, ctx, options: any = {}) {
|
||||
useSessionCookies: true,
|
||||
redirect: 'follow'
|
||||
} as any)
|
||||
|
||||
let settled = false
|
||||
|
||||
const timer = setTimeout(() => {
|
||||
@@ -6910,6 +6913,7 @@ async function finalizeGatewayDownload(res, statusCode, headers, ctx: any = {})
|
||||
|
||||
const disposition = headers['content-disposition'] || headers['Content-Disposition']
|
||||
const filename = filenameFromContentDisposition(disposition) || ctx.suggested || ctx.fallbackName
|
||||
|
||||
const result = await dialog.showSaveDialog(mainWindow, {
|
||||
defaultPath: filename,
|
||||
title: 'Save File'
|
||||
@@ -6967,10 +6971,12 @@ async function saveGatewayFile(payload: any = {}) {
|
||||
const suggested = String(payload.suggestedName || '').trim()
|
||||
const fallbackName = path.basename(filePath) || suggested || 'download'
|
||||
const ctx = { suggested, fallbackName }
|
||||
|
||||
const requestPath = pathWithGlobalRemoteProfile(`/api/fs/download?path=${encodeURIComponent(filePath)}`, profile, {
|
||||
globalRemote: globalRemoteActive(),
|
||||
profileRemoteOverride: profileHasRemoteOverride(profile)
|
||||
})
|
||||
|
||||
const url = `${connection.baseUrl}${requestPath}`
|
||||
|
||||
try {
|
||||
@@ -7002,10 +7008,13 @@ async function saveGatewayFileViaDataUrl(connection, profile, filePath, ctx: any
|
||||
profileRemoteOverride: profileHasRemoteOverride(profile)
|
||||
}
|
||||
)
|
||||
|
||||
const url = `${connection.baseUrl}${requestPath}`
|
||||
|
||||
const json = (
|
||||
connection.authMode === 'oauth' ? await fetchJsonViaOauthSession(url) : await fetchJson(url, connection.token)
|
||||
) as any
|
||||
|
||||
const dataUrl = json?.dataUrl
|
||||
|
||||
if (!dataUrl) {
|
||||
@@ -7014,6 +7023,7 @@ async function saveGatewayFileViaDataUrl(connection, profile, filePath, ctx: any
|
||||
|
||||
const buffer = parseDataUrlToBuffer(dataUrl)
|
||||
const filename = ctx.suggested || ctx.fallbackName
|
||||
|
||||
const result = await dialog.showSaveDialog(mainWindow, {
|
||||
defaultPath: filename,
|
||||
title: 'Save File'
|
||||
|
||||
@@ -319,7 +319,8 @@ function explicitToolArtifactKey(keyPath: string, producerTool: boolean): boolea
|
||||
.split('.')
|
||||
.filter(segment => segment && !/^\d+$/.test(segment))
|
||||
.some(
|
||||
segment => STRONG_TOOL_ARTIFACT_KEY_RE.test(segment) || (producerTool && PRODUCER_TOOL_ARTIFACT_KEY_RE.test(segment))
|
||||
segment =>
|
||||
STRONG_TOOL_ARTIFACT_KEY_RE.test(segment) || (producerTool && PRODUCER_TOOL_ARTIFACT_KEY_RE.test(segment))
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -154,7 +154,9 @@ describe('composer IME composition — send button visibility (#39614)', () => {
|
||||
composingRef.current = true
|
||||
}}
|
||||
onInput={event => {
|
||||
if (composingRef.current) {return}
|
||||
if (composingRef.current) {
|
||||
return
|
||||
}
|
||||
flushEditorToDraft(event.currentTarget)
|
||||
}}
|
||||
onKeyDown={handleKeyDown}
|
||||
|
||||
@@ -962,7 +962,12 @@ describe('overlayLiveLanes', () => {
|
||||
sessionCount: 1,
|
||||
groups: [
|
||||
lane({ id: '/www/app::branch::main', label: 'main', isMain: true, path: '/www/app', sessions: [session] }),
|
||||
lane({ id: '/www/app/.worktrees/feature', label: 'feature', path: '/www/app/.worktrees/feature', sessions: [] })
|
||||
lane({
|
||||
id: '/www/app/.worktrees/feature',
|
||||
label: 'feature',
|
||||
path: '/www/app/.worktrees/feature',
|
||||
sessions: []
|
||||
})
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -572,10 +572,7 @@ export function overlayRepoLanes(
|
||||
(placed.isMain && placedKey
|
||||
? lanes.find(
|
||||
g =>
|
||||
g.isMain &&
|
||||
pathKey(g.path) === placedKey &&
|
||||
!g.id.includes('::branch::') &&
|
||||
!g.id.includes('::kanban')
|
||||
g.isMain && pathKey(g.path) === placedKey && !g.id.includes('::branch::') && !g.id.includes('::kanban')
|
||||
)
|
||||
: undefined) ??
|
||||
(!placed.isMain && placedKey ? lanes.find(g => pathKey(g.path) === placedKey) : undefined)
|
||||
|
||||
@@ -22,7 +22,14 @@ import { Codicon } from '@/components/ui/codicon'
|
||||
import { ColorSwatches } from '@/components/ui/color-swatches'
|
||||
import { ConfirmDialog } from '@/components/ui/confirm-dialog'
|
||||
import { CopyButton } from '@/components/ui/copy-button'
|
||||
import { Dialog, DialogContent, DialogFooter, DialogHeader, DialogTitle, preventCloseButtonAutoFocus } from '@/components/ui/dialog'
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
preventCloseButtonAutoFocus
|
||||
} from '@/components/ui/dialog'
|
||||
import { Input } from '@/components/ui/input'
|
||||
import { renameSession } from '@/hermes'
|
||||
import { useI18n } from '@/i18n'
|
||||
|
||||
@@ -65,10 +65,7 @@ describe('session row details', () => {
|
||||
|
||||
it('omits zero counts from metadata so the sidebar stays clean', () => {
|
||||
expect(
|
||||
sessionRowDetails(
|
||||
session({ git_branch: null, message_count: 0, model: null, tool_call_count: 0 }),
|
||||
en
|
||||
)
|
||||
sessionRowDetails(session({ git_branch: null, message_count: 0, model: null, tool_call_count: 0 }), en)
|
||||
).toEqual({ metadata: '', preview: 'Explore Gmail-like density tiers for session rows.' })
|
||||
})
|
||||
|
||||
@@ -99,10 +96,7 @@ describe('session row details', () => {
|
||||
}
|
||||
|
||||
expect(
|
||||
sessionRowDetails(
|
||||
session({ git_branch: null, message_count: 3, model: null, tool_call_count: 5 }),
|
||||
ja
|
||||
)
|
||||
sessionRowDetails(session({ git_branch: null, message_count: 3, model: null, tool_call_count: 5 }), ja)
|
||||
).toEqual({
|
||||
metadata: '3 件のメッセージ · 5 件のツール呼び出し',
|
||||
preview: 'Explore Gmail-like density tiers for session rows.'
|
||||
|
||||
@@ -177,11 +177,7 @@ describe('refreshSessions identity + loading hygiene', () => {
|
||||
// both honor the tombstone, or a deleted platform thread resurrects.
|
||||
removed.ids = new Set(['tg-2'])
|
||||
listSidebarSessions.mockResolvedValue(
|
||||
sidebar(
|
||||
{ sessions: [] },
|
||||
[],
|
||||
[row('tg-1', { source: 'telegram' }), row('tg-2', { source: 'telegram' })]
|
||||
)
|
||||
sidebar({ sessions: [] }, [], [row('tg-1', { source: 'telegram' }), row('tg-2', { source: 'telegram' })])
|
||||
)
|
||||
|
||||
const { result } = renderHook(() => useSessionListActions({ profileScope: 'default' }))
|
||||
@@ -194,7 +190,11 @@ describe('refreshSessions identity + loading hygiene', () => {
|
||||
|
||||
// Per-platform pager: backend page still lists the doomed row.
|
||||
listAllProfileSessions.mockResolvedValue({
|
||||
sessions: [row('tg-1', { source: 'telegram' }), row('tg-2', { source: 'telegram' }), row('tg-3', { source: 'telegram' })],
|
||||
sessions: [
|
||||
row('tg-1', { source: 'telegram' }),
|
||||
row('tg-2', { source: 'telegram' }),
|
||||
row('tg-3', { source: 'telegram' })
|
||||
],
|
||||
total: 3
|
||||
})
|
||||
|
||||
|
||||
@@ -28,7 +28,14 @@ import { useOnProfileSwitch } from '../hooks/use-on-profile-switch'
|
||||
import { PanelEmpty } from '../overlays/panel'
|
||||
|
||||
import { ConfigField } from './config-field'
|
||||
import { clearsEnabledToolsets, enumOptionsFor, getNested, isExternalMemoryProvider, sectionFieldEntries, setNested } from './helpers'
|
||||
import {
|
||||
clearsEnabledToolsets,
|
||||
enumOptionsFor,
|
||||
getNested,
|
||||
isExternalMemoryProvider,
|
||||
sectionFieldEntries,
|
||||
setNested
|
||||
} from './helpers'
|
||||
import { MemoryConnect } from './memory/connect'
|
||||
import { ProviderConfigPanel } from './memory/provider-config-panel'
|
||||
import { ModelSettings, ModelSettingsSkeleton } from './model-settings'
|
||||
|
||||
@@ -68,11 +68,7 @@ export function useElapsedSeconds(active = true, timerKey?: string, since?: numb
|
||||
}
|
||||
}, [active, since, timerKey])
|
||||
|
||||
useViewedInterval(
|
||||
() => setElapsed(Math.max(0, Math.floor((Date.now() - start.current) / 1000))),
|
||||
1000,
|
||||
active
|
||||
)
|
||||
useViewedInterval(() => setElapsed(Math.max(0, Math.floor((Date.now() - start.current) / 1000))), 1000, active)
|
||||
|
||||
return elapsed
|
||||
}
|
||||
|
||||
@@ -191,6 +191,7 @@ export function FloatingPet() {
|
||||
// re-sent over the WebSocket on every backstop refresh.
|
||||
const held = $petInfo.get()
|
||||
const knownRevision = held.enabled && held.spritesheetBase64 ? held.spritesheetRevision : undefined
|
||||
|
||||
const next = await requestGateway<PetInfo & { spritesheetUnchanged?: boolean }>('pet.info', {
|
||||
knownRevision,
|
||||
profile: petProfile()
|
||||
@@ -253,10 +254,7 @@ export function FloatingPet() {
|
||||
// Always keep a timer. Event-capable backends use the slow backstop (same
|
||||
// contract as cron/sessions in use-background-sync); legacy keeps the
|
||||
// historical fast-while-inactive cadence.
|
||||
const timer = window.setInterval(
|
||||
pullIfVisible,
|
||||
petInfoPollIntervalMs(changeEventsAvailable, active)
|
||||
)
|
||||
const timer = window.setInterval(pullIfVisible, petInfoPollIntervalMs(changeEventsAvailable, active))
|
||||
|
||||
return () => {
|
||||
cancelled = true
|
||||
|
||||
@@ -13,10 +13,7 @@ export const PET_BACKSTOP_MS = 15_000
|
||||
/** Cold-start retries after the first connect pull (fail-open recovery). */
|
||||
export const PET_STARTUP_RETRY_MS = [1_000, 3_000, 8_000] as const
|
||||
|
||||
export function petInfoPollIntervalMs(
|
||||
changeEventsAvailable: boolean,
|
||||
active: boolean
|
||||
): number {
|
||||
export function petInfoPollIntervalMs(changeEventsAvailable: boolean, active: boolean): number {
|
||||
if (changeEventsAvailable) {
|
||||
return PET_BACKSTOP_MS
|
||||
}
|
||||
|
||||
@@ -251,12 +251,14 @@ describe('PetSprite RAF scheduling', () => {
|
||||
|
||||
it('draws sprite frames with bicubic smoothing for illustration art', () => {
|
||||
const raf = installRaf()
|
||||
|
||||
const ctxMock = {
|
||||
clearRect: vi.fn(),
|
||||
drawImage: vi.fn(),
|
||||
imageSmoothingEnabled: false,
|
||||
imageSmoothingQuality: 'low'
|
||||
} as unknown as CanvasRenderingContext2D
|
||||
|
||||
vi.spyOn(HTMLCanvasElement.prototype, 'getContext').mockReturnValue(ctxMock)
|
||||
|
||||
render(<PetSprite info={INFO} />)
|
||||
|
||||
@@ -21,12 +21,14 @@ export function useViewedInterval(callback: () => void, intervalMs: number, enab
|
||||
}
|
||||
|
||||
let intervalId: null | number = null
|
||||
|
||||
const stop = () => {
|
||||
if (intervalId !== null) {
|
||||
window.clearInterval(intervalId)
|
||||
intervalId = null
|
||||
}
|
||||
}
|
||||
|
||||
const sync = () => {
|
||||
const viewed = document.visibilityState === 'visible' && document.hasFocus()
|
||||
|
||||
|
||||
@@ -799,7 +799,8 @@ export const zh: Translations = {
|
||||
autosaveFailed: '自动保存失败',
|
||||
imported: '配置已导入',
|
||||
invalidJson: '配置 JSON 无效',
|
||||
toolsetsWipeConfirm: '确定移除所有已启用的工具集吗?这将禁用记忆、终端、网络搜索、委派以及大多数其他工具,直到你重新启用它们。',
|
||||
toolsetsWipeConfirm:
|
||||
'确定移除所有已启用的工具集吗?这将禁用记忆、终端、网络搜索、委派以及大多数其他工具,直到你重新启用它们。',
|
||||
keepAwakeTitle: '保持电脑唤醒',
|
||||
keepAwakeDesc: '阻止本机休眠,让长时间或通宵运行继续进行。屏幕仍可变暗。',
|
||||
attachmentSizeTitle: '预览 / 图片加载大小上限',
|
||||
|
||||
@@ -69,7 +69,9 @@ describe('requestModelOptions', () => {
|
||||
|
||||
vi.mocked(getGlobalModelOptions).mockResolvedValueOnce(restPayload)
|
||||
|
||||
await expect(requestModelOptions({ gateway: gateway as never, sessionId: 'session-1' })).resolves.toEqual(restPayload)
|
||||
await expect(requestModelOptions({ gateway: gateway as never, sessionId: 'session-1' })).resolves.toEqual(
|
||||
restPayload
|
||||
)
|
||||
expect(getGlobalModelOptions).toHaveBeenCalledWith({ explicitOnly: true })
|
||||
})
|
||||
|
||||
|
||||
@@ -5,9 +5,7 @@ import { persistBoolean, storedBoolean } from '@/lib/storage'
|
||||
const REASONING_COLLAPSED_BY_DEFAULT_STORAGE_KEY = 'hermes.desktop.reasoning.collapsedByDefault'
|
||||
|
||||
/** Desktop-local presentation preference; shared backend config must not be changed by a single window. */
|
||||
export const $reasoningCollapsedByDefault = atom(
|
||||
storedBoolean(REASONING_COLLAPSED_BY_DEFAULT_STORAGE_KEY, false)
|
||||
)
|
||||
export const $reasoningCollapsedByDefault = atom(storedBoolean(REASONING_COLLAPSED_BY_DEFAULT_STORAGE_KEY, false))
|
||||
|
||||
$reasoningCollapsedByDefault.subscribe(value => persistBoolean(REASONING_COLLAPSED_BY_DEFAULT_STORAGE_KEY, value))
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ const cases: Array<[string, string, string]> = [
|
||||
['DEL-space-DEL + char', '\x7f \x7fô', 'ô'],
|
||||
['trailing text after multi DEL', '\x7f\x7f\x7fươn', 'ươn'],
|
||||
['char then DEL then char fused', 'o\x7fô', 'ô'],
|
||||
['multiple syllable fused', 'vuon\x7f\x7f\x7fương', 'vương'],
|
||||
['multiple syllable fused', 'vuon\x7f\x7f\x7fương', 'vương']
|
||||
// CR/LF are intentionally NOT split (preserve paste/return semantics), so a
|
||||
// text token with an embedded CR is left whole; assert it is NOT split into
|
||||
// surviving letters here — that path is covered by the composer's return /
|
||||
|
||||
@@ -145,9 +145,27 @@ describe('Vietnamese Telex IME recomposition', () => {
|
||||
// Captured byte stream for Telex "vuonwg syx hanhj": each syllable injects a
|
||||
// U+202F marker, erases, and re-emits. Verified across read timings.
|
||||
const reads = [
|
||||
'v', 'u', 'o', NNBSP, '\x7f\x7f', '\x7f\u01B0\u01A1', 'n', 'g',
|
||||
' ', 's', 'y', NNBSP, '\x7f', '\x7f\u1EF9',
|
||||
' ', 'h', 'a', 'n', 'h', NNBSP, '\x7f\x7f\x7f\x7f\u1EA1nh'
|
||||
'v',
|
||||
'u',
|
||||
'o',
|
||||
NNBSP,
|
||||
'\x7f\x7f',
|
||||
'\x7f\u01B0\u01A1',
|
||||
'n',
|
||||
'g',
|
||||
' ',
|
||||
's',
|
||||
'y',
|
||||
NNBSP,
|
||||
'\x7f',
|
||||
'\x7f\u1EF9',
|
||||
' ',
|
||||
'h',
|
||||
'a',
|
||||
'n',
|
||||
'h',
|
||||
NNBSP,
|
||||
'\x7f\x7f\x7f\x7f\u1EA1nh'
|
||||
]
|
||||
|
||||
for (const gapMs of [0, 17, 25]) {
|
||||
@@ -240,4 +258,4 @@ describe('Fast-echo suppression reset (60ms window)', () => {
|
||||
const reads2 = [...reads, '\x7f', '\x7f']
|
||||
expect(await drive(reads2)).toBe('hel')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -266,12 +266,14 @@ class TurnController {
|
||||
|
||||
endReasoningPhase() {
|
||||
this.reasoningStreamingTimer = clear(this.reasoningStreamingTimer)
|
||||
|
||||
// Seal any open reasoning segment so its isLiveReasoning flag drops the
|
||||
// moment the reasoning phase ends — the panel must stop tracking the
|
||||
// turn's global reasoningActive, not stay "live" for the rest of the turn.
|
||||
if (this.reasoningSegmentIndex !== null) {
|
||||
this.syncReasoningSegment(false)
|
||||
}
|
||||
|
||||
patchTurnState({ reasoningActive: false, reasoningStreaming: false })
|
||||
}
|
||||
|
||||
|
||||
@@ -944,9 +944,11 @@ export function TextInput({
|
||||
// guard. Use a short real-time window that spans a recompose burst;
|
||||
// normal typing re-enables fast-echo via the append path below.
|
||||
inkRepaintedRef.current = true
|
||||
|
||||
if (inkRepaintResetTimer.current) {
|
||||
clearTimeout(inkRepaintResetTimer.current)
|
||||
}
|
||||
|
||||
inkRepaintResetTimer.current = setTimeout(() => {
|
||||
inkRepaintResetTimer.current = null
|
||||
inkRepaintedRef.current = false
|
||||
@@ -1446,10 +1448,12 @@ export function TextInput({
|
||||
// terminal baseline is synced again — clear any pending Ink-repaint
|
||||
// fast-echo suppression so normal backspace fast-echo resumes.
|
||||
inkRepaintedRef.current = false
|
||||
|
||||
if (inkRepaintResetTimer.current) {
|
||||
clearTimeout(inkRepaintResetTimer.current)
|
||||
inkRepaintResetTimer.current = null
|
||||
}
|
||||
|
||||
// ASCII-printable text advances the physical cursor by exactly
|
||||
// text.length cells (canFastAppendShape rejects non-ASCII,
|
||||
// wide chars, newlines). Notify Ink so the cached displayCursor
|
||||
|
||||
Reference in New Issue
Block a user