153 lines
4.3 KiB
JavaScript
153 lines
4.3 KiB
JavaScript
import test from 'node:test'
|
|
import assert from 'node:assert/strict'
|
|
import { readFileSync } from 'node:fs'
|
|
import { fileURLToPath } from 'node:url'
|
|
import { dirname, join } from 'node:path'
|
|
import vm from 'node:vm'
|
|
|
|
const dir = dirname(fileURLToPath(import.meta.url))
|
|
|
|
/**
|
|
* @param {string} rel
|
|
* @param {string[]} names
|
|
*/
|
|
function loadFns(rel, names) {
|
|
const src = readFileSync(join(dir, rel), 'utf8')
|
|
const sandbox = {
|
|
console,
|
|
bareEditSgr: (cls, on) => (on ? '\x1b[2m' : ''),
|
|
EDIT_ANSI_RESET: '\x1b[0m',
|
|
bareEditChunkBytes: (chunk) => {
|
|
if (typeof chunk === 'string') {
|
|
const out = []
|
|
for (let i = 0; i < chunk.length; i++) out.push(chunk.charCodeAt(i) & 0xff)
|
|
return out
|
|
}
|
|
return []
|
|
},
|
|
bareEditTryConsumeKey: () => null
|
|
}
|
|
vm.createContext(sandbox)
|
|
vm.runInContext(src, sandbox)
|
|
/** @type {Record<string, Function>} */
|
|
const api = {}
|
|
for (const n of names) {
|
|
assert.equal(typeof sandbox[n], 'function', 'missing ' + n)
|
|
api[n] = sandbox[n]
|
|
}
|
|
return api
|
|
}
|
|
|
|
test('markdown renders headings lists and bold', () => {
|
|
const api = loadFns('../lib/agent-markdown.js', ['bareAgentRenderMarkdown'])
|
|
const out = api.bareAgentRenderMarkdown(
|
|
'# Title\n\nI use **bold** and `code`.\n\n1. One\n2. Two\n\n- Alpha\n- Beta\n',
|
|
{ useColor: false, width: 72 }
|
|
)
|
|
assert.match(out, /Title/)
|
|
assert.match(out, /bold/)
|
|
assert.match(out, /code/)
|
|
assert.match(out, /1\. One/)
|
|
assert.match(out, /• Alpha/)
|
|
})
|
|
|
|
test('markdown fences keep code body', () => {
|
|
const api = loadFns('../lib/agent-markdown.js', ['bareAgentRenderMarkdown'])
|
|
const out = api.bareAgentRenderMarkdown('```js\nconst x = 1\n```\n', {
|
|
useColor: false,
|
|
width: 72
|
|
})
|
|
assert.match(out, /const x = 1/)
|
|
assert.match(out, /js/)
|
|
})
|
|
|
|
test('think panel scrollbar and scroll keys', () => {
|
|
const api = loadFns('../lib/agent-think-panel.js', [
|
|
'bareAgentCreateThinkPanel',
|
|
'bareAgentThinkScrollbar'
|
|
])
|
|
const sb = api.bareAgentThinkScrollbar(4, 20, 0, false)
|
|
assert.equal(sb.length, 4)
|
|
assert.ok(sb.some((c) => c === '#'))
|
|
|
|
/** @type {string[]} */
|
|
const writes = []
|
|
const panel = api.bareAgentCreateThinkPanel(
|
|
{ env: { COLUMNS: '72', BARE_OS_AGENT_ASCII: '1' } },
|
|
{ isTTY: true, columns: 72, write: () => true },
|
|
{
|
|
useColor: false,
|
|
bodyLines: 4,
|
|
write: (_c, _o, s) => writes.push(s)
|
|
}
|
|
)
|
|
for (let i = 0; i < 20; i++) {
|
|
panel.append('Line number ' + i + ' about tools and skills.\n')
|
|
}
|
|
assert.ok(writes.length >= 1)
|
|
const before = writes.length
|
|
panel.scrollUp(3)
|
|
assert.ok(writes.length > before)
|
|
panel.handleKey({ type: 'nav', key: 'pageup' })
|
|
panel.seal()
|
|
assert.ok(panel.hasContent())
|
|
panel.setStatus('answering…')
|
|
panel.clearStatus()
|
|
})
|
|
|
|
test('term cols use full width without 120 cap', () => {
|
|
const api = loadFns('../lib/agent-think-panel.js', [
|
|
'bareAgentResolveTermCols'
|
|
])
|
|
const w = api.bareAgentResolveTermCols(
|
|
{ env: { COLUMNS: '80' } },
|
|
{ columns: 200 }
|
|
)
|
|
assert.equal(w, 200)
|
|
const w2 = api.bareAgentResolveTermCols({ env: { COLUMNS: '160' } }, {})
|
|
assert.equal(w2, 160)
|
|
})
|
|
|
|
test('empty think panel never draws', () => {
|
|
const api = loadFns('../lib/agent-think-panel.js', [
|
|
'bareAgentCreateThinkPanel'
|
|
])
|
|
/** @type {string[]} */
|
|
const writes = []
|
|
const panel = api.bareAgentCreateThinkPanel(
|
|
{ env: { COLUMNS: '100' } },
|
|
{ isTTY: true, columns: 100, write: () => true },
|
|
{
|
|
useColor: false,
|
|
bodyLines: 4,
|
|
write: (_c, _o, s) => writes.push(s)
|
|
}
|
|
)
|
|
panel.append('\n\n \n')
|
|
panel.seal()
|
|
panel.setStatus('should not show')
|
|
assert.equal(writes.length, 0)
|
|
assert.equal(panel.hasContent(), false)
|
|
panel.append('real thought')
|
|
assert.ok(writes.length >= 1)
|
|
assert.ok(panel.hasContent())
|
|
})
|
|
|
|
test('think tag splitter still works', () => {
|
|
const api = loadFns('../lib/agent-think-panel.js', [
|
|
'bareAgentCreateThinkTagSplitter'
|
|
])
|
|
/** @type {string[]} */
|
|
const think = []
|
|
/** @type {string[]} */
|
|
const content = []
|
|
const split = api.bareAgentCreateThinkTagSplitter({
|
|
onThink: (s) => think.push(s),
|
|
onContent: (s) => content.push(s)
|
|
})
|
|
split.push('<think>plan</think>\nAnswer **here**')
|
|
split.flush()
|
|
assert.equal(think.join(''), 'plan')
|
|
assert.equal(content.join(''), '\nAnswer **here**')
|
|
})
|