mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-15 14:22:43 +00:00
Bring apps/desktop and ui-tui to a clean state for typecheck, eslint,
and prettier:
- Run prettier across both trees (printWidth/wrap drift; prettier is not
CI-enforced for these JS projects, so main had accumulated drift).
- Apply eslint --fix for padding-line-between-statements and perfectionist
import/export sorting.
- Manual fixes for non-auto-fixable rules:
- remove unused node:net import in electron/main.cjs (uses Electron net)
- replace inline `typeof import(...)` annotations with top-level
`import type * as EnvModule` in two ui-tui test files
- scoped eslint-disable no-control-regex on intentional sentinel/ANSI
regexes (mathUnicode.ts, text.ts)
- resolve react-hooks/exhaustive-deps per-case: correct swapped/missing
deps, collapse redundant session.* members, and justified disables on
settings mount-only data-load effects to preserve run-once behavior
No behavior changes; test pass/fail counts are unchanged from the main
baseline.
74 lines
2.3 KiB
TypeScript
74 lines
2.3 KiB
TypeScript
import React from 'react'
|
|
import { describe, expect, it, vi } from 'vitest'
|
|
|
|
import { StatusRule } from '../components/appChrome.js'
|
|
import type * as EnvModule from '../config/env.js'
|
|
import { DEFAULT_THEME } from '../theme.js'
|
|
|
|
// DEV_CREDITS_MODE is a module-load-time constant (config/env.ts reads
|
|
// process.env.HERMES_DEV_CREDITS exactly once, at import). Mutating process.env
|
|
// inside a test can't flip it after the module is loaded — so mock the module to
|
|
// the dev-on value for this file. vitest hoists vi.mock above the imports, so
|
|
// appChrome picks up the mocked flag. Lives in its own file so the override
|
|
// stays scoped (the other StatusRule tests run with the real, dev-off value).
|
|
vi.mock('../config/env.js', async importOriginal => {
|
|
const actual = await importOriginal<typeof EnvModule>()
|
|
|
|
return { ...actual, DEV_CREDITS_MODE: true }
|
|
})
|
|
|
|
type ReactNodeLike = React.ReactNode
|
|
|
|
const textContent = (node: ReactNodeLike): string => {
|
|
if (node === null || node === undefined || typeof node === 'boolean') {
|
|
return ''
|
|
}
|
|
|
|
if (typeof node === 'string' || typeof node === 'number') {
|
|
return String(node)
|
|
}
|
|
|
|
if (Array.isArray(node)) {
|
|
return node.map(textContent).join('')
|
|
}
|
|
|
|
if (React.isValidElement(node)) {
|
|
return textContent(node.props.children)
|
|
}
|
|
|
|
return ''
|
|
}
|
|
|
|
const baseProps = {
|
|
bgCount: 0,
|
|
busy: false,
|
|
cols: 100,
|
|
cwdLabel: '~/repo',
|
|
liveSessionCount: 0,
|
|
model: 'opus-4.8',
|
|
sessionStartedAt: null,
|
|
status: 'ready',
|
|
statusColor: DEFAULT_THEME.color.ok,
|
|
t: DEFAULT_THEME,
|
|
turnStartedAt: null,
|
|
usage: { context_max: 200_000, context_percent: 25, context_used: 50_000, total: 50_000 },
|
|
voiceLabel: ''
|
|
}
|
|
|
|
describe('StatusRule dev-credits banner (HERMES_DEV_CREDITS on)', () => {
|
|
it('keeps the dev-credits banner visible alongside a notice', () => {
|
|
const element = StatusRule({
|
|
...baseProps,
|
|
notice: { key: 'credits.90', kind: 'sticky', level: 'warn', text: '⚠ 90% used' },
|
|
usage: { ...baseProps.usage, dev_credits_spent_micros: 12_345 }
|
|
})
|
|
|
|
const rendered = textContent(element)
|
|
|
|
// The notice and the dev banner coexist …
|
|
expect(rendered).toContain('⚠ 90% used')
|
|
expect(rendered).toContain('(dev credits)')
|
|
// … and the Δ spend segment renders (12345 micros → 1.2¢).
|
|
expect(rendered).toContain('Δ')
|
|
})
|
|
})
|