fmt(js): npm run fix on merge (#86751)

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
hermes-seaeye[bot]
2026-08-15 06:22:02 +00:00
committed by GitHub
parent 0904f50e3e
commit 0807673e1f
15 changed files with 110 additions and 47 deletions
@@ -9,8 +9,7 @@ import assert from 'node:assert/strict'
import { test } from 'vitest'
import type {
ConnectionRegistry} from './connection-registry';
import type { ConnectionRegistry } from './connection-registry'
import {
agentHandle,
connectionIdForLabel,
@@ -75,7 +74,8 @@ test('uniqueLabel counts up (never "X 2 2") and clamps long candidates', () => {
test('save rejects the reserved "local" id on non-local kinds', () => {
assert.throws(
() => normalizeConnectionInput({ id: 'local', kind: 'remote', label: 'Sneaky', url: 'http://x:1' }, emptyRegistry()),
() =>
normalizeConnectionInput({ id: 'local', kind: 'remote', label: 'Sneaky', url: 'http://x:1' }, emptyRegistry()),
/reserved/
)
})
@@ -108,7 +108,14 @@ test('token only persists on token-auth remotes; oauth/cloud drop it', () => {
// --- mergeConnectionInput (edit inheritance) ---
test('merge preserves fields the editor does not carry (org, ssh extras)', () => {
const cloud = { authMode: 'oauth' as const, id: 'c', kind: 'cloud' as const, label: 'Cloud', org: 'nous', url: 'https://a.cloud' }
const cloud = {
authMode: 'oauth' as const,
id: 'c',
kind: 'cloud' as const,
label: 'Cloud',
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')
@@ -262,8 +269,22 @@ test('normalizeRegistry round-trips a valid registry unchanged in shape', () =>
primary: 'homelab',
connections: [
{ id: 'local', kind: 'local', label: 'This device' },
{ id: 'homelab', kind: 'remote', label: 'Homelab', url: 'http://10.0.0.5:9119', authMode: 'token', token: { v: 1 } },
{ id: 'cloud-1', kind: 'cloud', label: 'Hermes Cloud', url: 'https://a.hermes.cloud', authMode: 'oauth', org: 'nous' },
{
id: 'homelab',
kind: 'remote',
label: 'Homelab',
url: 'http://10.0.0.5:9119',
authMode: 'token',
token: { v: 1 }
},
{
id: 'cloud-1',
kind: 'cloud',
label: 'Hermes Cloud',
url: 'https://a.hermes.cloud',
authMode: 'oauth',
org: 'nous'
},
{ id: 'spark', kind: 'ssh', label: 'Spark', host: 'spark1', user: 'tek', port: 2222 }
]
}
@@ -272,7 +293,10 @@ test('normalizeRegistry round-trips a valid registry unchanged in shape', () =>
assert.equal(registry.primary, 'homelab')
assert.equal(registry.connections.length, 4)
assert.deepEqual(registry.connections.map(c => c.id), ['local', 'homelab', 'cloud-1', 'spark'])
assert.deepEqual(
registry.connections.map(c => c.id),
['local', 'homelab', 'cloud-1', 'spark']
)
assert.deepEqual(registry.connections[1].token, { v: 1 })
assert.equal(registry.connections[3].port, 2222)
})
+25 -5
View File
@@ -27,7 +27,13 @@
* these into the IPC layer and owns file I/O + secret encryption.
*/
import { hostLabelFromBaseUrl, modeIsRemoteLike, normalizeRemoteBaseUrl, normalizeSshConfig, normAuthMode } from './connection-config'
import {
hostLabelFromBaseUrl,
modeIsRemoteLike,
normalizeRemoteBaseUrl,
normalizeSshConfig,
normAuthMode
} from './connection-config'
export const REGISTRY_VERSION = 2
@@ -204,7 +210,12 @@ export function normalizeConnectionInput(input: ConnectionInput, registry: Conne
throw new Error('The id "local" is reserved for the local connection.')
}
const id = input.id || connectionIdForLabel(label, registry.connections.map(c => c.id))
const id =
input.id ||
connectionIdForLabel(
label,
registry.connections.map(c => c.id)
)
if (kind === 'ssh') {
const ssh = normalizeSshConfig({
@@ -436,7 +447,10 @@ export function migrateV1ToRegistry(v1: unknown): ConnectionRegistry {
)
const entry: RegistryConnection = {
id: connectionIdForLabel(label, connections.map(c => c.id)),
id: connectionIdForLabel(
label,
connections.map(c => c.id)
),
kind,
label,
url,
@@ -473,12 +487,18 @@ export function migrateV1ToRegistry(v1: unknown): ConnectionRegistry {
return existing
}
const label = uniqueLabel(ssh.host, connections.map(c => c.label))
const label = uniqueLabel(
ssh.host,
connections.map(c => c.label)
)
const { mode: _mode, ...sshFields } = ssh
const entry: RegistryConnection = {
id: connectionIdForLabel(label, connections.map(c => c.id)),
id: connectionIdForLabel(
label,
connections.map(c => c.id)
),
kind: 'ssh',
label,
...sshFields
+1
View File
@@ -7248,6 +7248,7 @@ async function discoverCloudAgents(org?: string) {
const err = new Error(
'Your Hermes Cloud session has expired. Open Settings → Gateway and sign in again.'
) as any
err.needsCloudLogin = true
err.cause = error
throw err
+1
View File
@@ -362,6 +362,7 @@ export function observeUpdaterHandoff(
deps: ObserveUpdaterHandoffDeps = {}
): Promise<UpdaterHandoffOutcome> {
const setTimeoutFn = deps.setTimeoutFn ?? setTimeout
const clearTimeoutFn =
deps.clearTimeoutFn ?? ((timer: unknown) => clearTimeout(timer as ReturnType<typeof setTimeout>))
@@ -346,7 +346,11 @@ function CronJobSidebarRow({
onClick={onTrigger}
type="button"
>
{busy ? <GlyphSpinner ariaLabel={c.triggerNow} className="text-[0.75rem]" /> : <Codicon name="zap" size="0.75rem" />}
{busy ? (
<GlyphSpinner ariaLabel={c.triggerNow} className="text-[0.75rem]" />
) : (
<Codicon name="zap" size="0.75rem" />
)}
</button>
</Tip>
<Tip label={c.manage}>
@@ -161,7 +161,9 @@ export const VirtualSessionList: FC<VirtualSessionListProps> = ({
)}
ref={scrollerRef}
>
<div className="relative" style={{ height: `${totalSize}px` }}>{rows}</div>
<div className="relative" style={{ height: `${totalSize}px` }}>
{rows}
</div>
</div>
)
}
@@ -143,9 +143,7 @@ describe('mutateAndRefreshCronJobs', () => {
it('allows overlapping same-profile mutations to authoritatively refresh', async () => {
const first = deferred<string>()
const second = deferred<string>()
getCronJobs
.mockResolvedValueOnce([{ id: 'after-second' }])
.mockResolvedValueOnce([{ id: 'after-both' }])
getCronJobs.mockResolvedValueOnce([{ id: 'after-second' }]).mockResolvedValueOnce([{ id: 'after-both' }])
const firstResult = mutateAndRefreshCronJobs('work', () => first.promise)
const secondResult = mutateAndRefreshCronJobs('work', () => second.promise)
+3 -8
View File
@@ -18,10 +18,7 @@ export interface CronMutationRefreshResult<T> extends CronTriggerRefreshResult {
value: T | null
}
async function refreshForGeneration(
profile: string,
request: CronJobsRequest
): Promise<CronTriggerRefreshResult> {
async function refreshForGeneration(profile: string, request: CronJobsRequest): Promise<CronTriggerRefreshResult> {
try {
const jobs = await getCronJobs(profile)
@@ -90,9 +87,7 @@ export async function triggerAndRefreshCronJobs(
jobId: string,
profile: 'all' | string
): Promise<CronTriggerRefreshResult> {
const { value: _value, ...result } = await mutateAndRefreshCronJobs(profile, () =>
triggerCronJob(jobId)
)
const { value: _value, ...result } = await mutateAndRefreshCronJobs(profile, () => triggerCronJob(jobId))
return result
}
}
+16 -6
View File
@@ -541,9 +541,7 @@ export function CronView({ onClose, onOpenSession, setStatusbarItemGroup: _setSt
setDeleting(true)
try {
const { refreshError, stale } = await mutateAndRefreshCronJobs(profile, () =>
deleteCronJob(pendingDelete.id)
)
const { refreshError, stale } = await mutateAndRefreshCronJobs(profile, () => deleteCronJob(pendingDelete.id))
if (stale) {
return
@@ -564,7 +562,11 @@ export function CronView({ onClose, onOpenSession, setStatusbarItemGroup: _setSt
async function handleEditorSave(values: EditorValues) {
if (editor.mode === 'create') {
const { value: created, refreshError, stale } = await mutateAndRefreshCronJobs(profile, () =>
const {
value: created,
refreshError,
stale
} = await mutateAndRefreshCronJobs(profile, () =>
createCronJob({
prompt: values.prompt,
schedule: values.schedule,
@@ -586,7 +588,11 @@ export function CronView({ onClose, onOpenSession, setStatusbarItemGroup: _setSt
} else if (editor.mode === 'edit') {
const scriptOnlyJob = jobIsScriptOnly(editor.job)
const { value: updated, refreshError, stale } = await mutateAndRefreshCronJobs(profile, () =>
const {
value: updated,
refreshError,
stale
} = await mutateAndRefreshCronJobs(profile, () =>
updateCronJob(editor.job.id, cronEditorUpdates(values, { scriptOnlyJob }))
)
@@ -612,7 +618,11 @@ export function CronView({ onClose, onOpenSession, setStatusbarItemGroup: _setSt
async function handleBlueprintCreate(blueprint: AutomationBlueprint, values: Record<string, string>) {
const writableProfile = profileScope === ALL_PROFILES ? 'default' : profileScope
const { value: job, refreshError, stale } = await mutateAndRefreshCronJobs(profile, () =>
const {
value: job,
refreshError,
stale
} = await mutateAndRefreshCronJobs(profile, () =>
instantiateAutomationBlueprint({ blueprint: blueprint.key, values }, writableProfile)
)
@@ -12,7 +12,11 @@ import { translateNow } from '@/i18n'
import { type GatewayEventPayload, textPart } from '@/lib/chat-messages'
import { coerceGatewayText, coerceThinkingText, normalizePersonalityValue } from '@/lib/chat-runtime'
import { playCompletionSound } from '@/lib/completion-sound'
import { approvalReplaySessionId, resolveGatewayEventSessionId, UNSCOPED_STREAM_EVENT_TYPES } from '@/lib/gateway-events'
import {
approvalReplaySessionId,
resolveGatewayEventSessionId,
UNSCOPED_STREAM_EVENT_TYPES
} from '@/lib/gateway-events'
import { triggerHaptic } from '@/lib/haptics'
import { modelOptionsQueryKey } from '@/lib/model-options'
import { isProviderSetupErrorMessage } from '@/lib/provider-setup-errors'
@@ -577,7 +577,11 @@ const ThreadMessageListInner: FC<ThreadMessageListProps> = ({
// can be overwritten by another mounted pane; leave a scrolled-up reader
// exactly where they were.
useEffect(
() => subscribeToThreadForeground(() => isAtBottom, () => void scrollToBottom()),
() =>
subscribeToThreadForeground(
() => isAtBottom,
() => void scrollToBottom()
),
[isAtBottom, scrollToBottom]
)
+1 -7
View File
@@ -1,12 +1,6 @@
import { beforeEach, describe, expect, it } from 'vitest'
import {
$cronJobs,
beginCronJobsRequest,
commitCronJobsRequest,
setCronJobs,
updateCronJobs
} from './cron'
import { $cronJobs, beginCronJobsRequest, commitCronJobsRequest, setCronJobs, updateCronJobs } from './cron'
const oldJob = { id: 'old' } as never
const newJob = { id: 'new' } as never
@@ -91,12 +91,12 @@ describe('skillTouchedInMessages', () => {
})
it('matches qualified skill names (category/name, plugin:name)', () => {
expect(skillTouchedInMessages('hermes-agent-dev', [toolCall('skill_view', { name: 'github/hermes-agent-dev' })])).toBe(
true
)
expect(skillTouchedInMessages('writing-plans', [toolCall('skill_view', { name: 'superpowers:writing-plans' })])).toBe(
true
)
expect(
skillTouchedInMessages('hermes-agent-dev', [toolCall('skill_view', { name: 'github/hermes-agent-dev' })])
).toBe(true)
expect(
skillTouchedInMessages('writing-plans', [toolCall('skill_view', { name: 'superpowers:writing-plans' })])
).toBe(true)
})
it('falls back to argsText when args were not parsed', () => {
@@ -149,7 +149,11 @@ export function skillTouchedInMessages(skillName: string, messages: readonly Cha
for (const message of messages) {
for (const part of message.parts) {
if (part.type === 'tool-call' && SKILL_TOOL_NAMES.has(part.toolName) && argNamesSkill(skillArgName(part), skillName)) {
if (
part.type === 'tool-call' &&
SKILL_TOOL_NAMES.has(part.toolName) &&
argNamesSkill(skillArgName(part), skillName)
) {
return true
}
+2
View File
@@ -50,6 +50,7 @@ function workspaceManifests(): { name: string, manifest: Manifest }[] {
for (const pattern of patterns) {
// The globs in use are plain paths or a single trailing ``/*``.
const parent = pattern.endsWith('/*') ? path.join(REPO_ROOT, pattern.slice(0, -2)) : null
const dirs = parent === null
? [pattern]
: fs.existsSync(parent)
@@ -78,6 +79,7 @@ test('workspaces declaring react and react-dom pin them to the same exact versio
if (react !== reactDom) {
offenders.push(`${name} declares react"${react}" but react-dom"${reactDom}"`)
continue
}