Repository navigation
Expand file tree
/
Copy pathtest.mjs
More file actions
147 lines (135 loc) · 6.71 KB
/
Copy pathtest.mjs
File metadata and controls
147 lines (135 loc) · 6.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// Smoke test for opencode-go.mjs — run from this directory: node test.mjs
// Parsers and formatting are checked against fixtures (no network). The live
// sections self-skip when there is no API key / no console cache to test.
import assert from 'node:assert'
import { readFileSync } from 'node:fs'
import { homedir } from 'node:os'
import { join } from 'node:path'
const mod = await import(new URL('./opencode-go.mjs', import.meta.url))
const { resolveKey, fetchUsage, cardRows, summarize, summarizeConsole, consoleCardRows, fmtDur } = mod
const HERMES_HOME =
(process.env.HERMES_HOME && process.env.HERMES_HOME.trim()) || join(homedir(), '.hermes')
// 0) degenerate payloads must not throw
summarize(null)
summarize({})
summarize({ usage: {} })
summarizeConsole(null)
summarizeConsole({})
summarizeConsole({ error: 'auth-expired' })
summarizeConsole({ meters: {} })
console.log('degenerate summarize: ok')
// 1) env priority when present
process.env.OPENCODE_GO_API_KEY = 'env-test-key'
assert.strictEqual(await resolveKey(), 'env-test-key')
delete process.env.OPENCODE_GO_API_KEY
console.log('resolveKey (env wins): ok')
// 2) tolerant parsing — live shape plus resetInSec / fraction variants
const sample = {
usage: {
rolling: { status: 'ok', percent: 3, resetsAt: '2026-09-23T05:00:27.116Z' },
weekly: { percent: 7, resetInSec: 3600 },
monthly: { usedPercent: 0.55 }
}
}
const parsed = summarize(sample, 1000)
assert.strictEqual(Math.round(parsed.rolling.pct), 3)
assert.strictEqual(parsed.rolling.resetAt, Date.parse('2026-09-23T05:00:27.116Z'))
assert.strictEqual(parsed.weekly.resetAt, 1000 + 3600 * 1000)
assert.strictEqual(Math.round(parsed.monthly.pct), 55)
assert.strictEqual(parsed.monthly.resetAt, null)
console.log('variant parsing: ok')
// 3) console cache parsing — micro-cent strings, month falls back to endsAt
const fixture = {
fetchedAt: Date.now(),
error: null,
endsAt: '2026-10-08T05:21:40.000Z',
meters: {
fiveHour: { usedMicroCents: '0', limitMicroCents: '1200000000', resetsAt: '2026-09-23T10:04:27.180Z' },
week: { usedMicroCents: '220000000', limitMicroCents: '3000000000', resetsAt: '2026-09-28T00:00:00.000Z' },
month: { usedMicroCents: '3317000000', limitMicroCents: '6000000000' }
}
}
const cons = summarizeConsole(fixture)
assert.strictEqual(cons.month.usedUSD, 33.17)
assert.strictEqual(cons.month.limitUSD, 60)
assert.ok(Math.abs(cons.month.pct - 55.2833) < 0.001)
assert.strictEqual(cons.month.resetAt, Date.parse('2026-10-08T05:21:40.000Z'), 'month reset falls back to endsAt')
assert.strictEqual(cons.fiveHour.usedUSD, 0)
console.log('console fixture parse: ok')
// 3a) dollar rows — header badge, $ formatting, width budget
const consRows = consoleCardRows(cons, Date.now())
assert.ok(consRows[0].map(([t]) => t).join('').includes(' · Go'), 'header should carry the · Go badge')
let consMax = 0
const consLines = []
for (const segments of consRows) {
const line = segments.map(([text]) => text).join('')
consLines.push(line)
consMax = Math.max(consMax, line.length)
console.log('|' + line + '| len=' + line.length + ' tones=' + segments.map(([, tone]) => tone).join(','))
}
assert.ok(consMax <= 44, 'console rows must fit the card inner width (got ' + consMax + ')')
assert.ok(consLines.some(l => l.includes('$33.17/$60')), 'cap should lose the fraction: $33.17/$60')
assert.ok(consLines.some(l => l.includes('$0.00/$12')), 'rolling dollars right-aligned: $0.00/$12')
// 3b) severity ladder: 55% → warn (bar + pct), 90% → error, 30% → ok
const toneOf = (rows, label) => {
const row = rows.find(r => r[0][0].trim() === label)
return { bar: row[1][1], pct: row[3][1] }
}
assert.deepStrictEqual(toneOf(consRows, 'month'), { bar: 'warn', pct: 'warn' }, '55% must read warn (50/80 ladder)')
const high = { ...fixture, meters: { ...fixture.meters, month: { usedMicroCents: '5400000000', limitMicroCents: '6000000000' } } }
const low = { ...fixture, meters: { ...fixture.meters, month: { usedMicroCents: '1800000000', limitMicroCents: '6000000000' } } }
assert.strictEqual(toneOf(consoleCardRows(summarizeConsole(high), Date.now()), 'month').bar, 'error')
assert.strictEqual(toneOf(consoleCardRows(summarizeConsole(low), Date.now()), 'month').bar, 'ok')
console.log('severity ladder: ok (30%→ok, 55%→warn, 90%→error)')
// 3c) worst-case width: a fresh cycle (29d 23h left) must still fit
const T0 = Date.UTC(2026, 8, 23, 6, 0, 0)
const wide = summarizeConsole({
fetchedAt: T0,
error: null,
endsAt: new Date(T0 + (29 * 24 + 23) * 3600_000).toISOString(),
meters: {
fiveHour: { usedMicroCents: '1200000000', limitMicroCents: '1200000000', resetsAt: new Date(T0 + 5 * 3600_000).toISOString() },
week: { usedMicroCents: '3000000000', limitMicroCents: '3000000000', resetsAt: new Date(T0 + 7 * 24 * 3600_000).toISOString() },
month: { usedMicroCents: '6000000000', limitMicroCents: '6000000000' }
}
})
let wideMax = 0
for (const segments of consoleCardRows(wide, T0)) {
const line = segments.map(([text]) => text).join('')
wideMax = Math.max(wideMax, line.length)
console.log('|' + line + '| len=' + line.length)
}
assert.ok(wideMax <= 44, 'worst case must fit (got ' + wideMax + ')')
console.log('worst-case width: ' + wideMax)
// 4) live sections — only when this machine is actually set up
const key = await resolveKey()
if (!key) {
console.log('SKIP live usage fetch — no API key (set OPENCODE_GO_API_KEY)')
} else {
const snap = await fetchUsage(key)
assert.ok(snap.rolling || snap.weekly || snap.monthly, 'live response should carry at least one window')
for (const [name, w] of [['rolling', snap.rolling], ['weekly', snap.weekly], ['monthly', snap.monthly]]) {
if (w) console.log(name + ':', Math.round(w.pct) + '%', '| resets in', fmtDur(w.resetAt - Date.now()))
}
const rows = cardRows(snap, Date.now())
let maxLen = 0
for (const segments of rows) {
const line = segments.map(([text]) => text).join('')
maxLen = Math.max(maxLen, line.length)
console.log('|' + line + '| len=' + line.length)
}
assert.ok(maxLen <= 44, 'all rows must fit the card inner width (got ' + maxLen + ')')
assert.ok(rows[0].map(([t]) => t).join('').includes(' · Go'), 'header badge in fallback mode too')
}
let liveCache = null
try {
liveCache = JSON.parse(readFileSync(join(HERMES_HOME, 'opencode-go', 'console.json'), 'utf8'))
} catch {}
if (liveCache) {
const liveCons = summarizeConsole(liveCache)
assert.ok(liveCons && !liveCons.error && liveCons.month, 'live console cache should parse')
console.log('live console: month $' + liveCons.month.usedUSD.toFixed(2) + '/$' + liveCons.month.limitUSD.toFixed(2))
} else {
console.log('SKIP live console cache — run fetch_console.mjs --extract first')
}
console.log('OK — parsers, formatting, severity and width budgets verified end to end')