kilo-loop/test/new-plan.test.mjs
2026-09-13 22:38:01 +03:00

71 lines
2.6 KiB
JavaScript

import { test } from 'node:test'
import assert from 'node:assert/strict'
import fs from 'node:fs'
import os from 'node:os'
import path from 'node:path'
import { execFileSync } from 'node:child_process'
import { fileURLToPath } from 'node:url'
import { discoverGoalFiles } from '../src/goals.mjs'
const SCRIPT = fileURLToPath(new URL('../new-plan.mjs', import.meta.url))
function tmpProject() {
return fs.mkdtempSync(path.join(os.tmpdir(), 'kilo-new-plan-'))
}
function run(args, project) {
return execFileSync(process.execPath, [SCRIPT, ...args, '--project', project], { encoding: 'utf8' })
}
test('new-plan writes a discoverable plan from the project template', () => {
const project = tmpProject()
fs.mkdirSync(path.join(project, '.kilo', 'templates'), { recursive: true })
fs.writeFileSync(
path.join(project, '.kilo', 'templates', 'plan.md'),
'# {{TITLE}}\n\n## Stages (kilo-loop)\n\n- [ ] Ship it :: verify: echo ok :: acceptance: shipped\n',
)
const out = run(['My Feature'], project).trim()
const abs = path.join(project, out)
assert.ok(fs.existsSync(abs), `plan file exists: ${out}`)
assert.match(path.basename(out), /^\d+-my-feature\.md$/)
const body = fs.readFileSync(abs, 'utf8')
assert.match(body, /^# My Feature$/m)
assert.match(body, /- \[ \] Ship it/)
// The whole point: kilo-loop must discover it.
assert.ok(discoverGoalFiles(project).some((f) => path.resolve(f) === path.resolve(abs)))
})
test('new-plan falls back to a built-in template when the project has none', () => {
const project = tmpProject()
const out = run(['Standalone'], project).trim()
const body = fs.readFileSync(path.join(project, out), 'utf8')
assert.match(body, /^# Standalone$/m)
assert.match(body, /## Stages \(kilo-loop\)/)
assert.match(body, /- \[ \] Stage 1/)
})
test('new-plan --print does not write a file', () => {
const project = tmpProject()
const out = run(['Preview only', '--print'], project)
assert.match(out, /^# Preview only$/m)
assert.equal(fs.existsSync(path.join(project, '.kilo', 'plans')), false)
})
test('new-plan refuses to overwrite without --force', () => {
const project = tmpProject()
const first = run(['Same', '--slug', 'same', '--epoch', '1700000000000'], project).trim()
assert.equal(first, '.kilo/plans/1700000000000-same.md')
assert.throws(() => run(['Same', '--slug', 'same', '--epoch', '1700000000000'], project), /already exists/)
// --force makes it succeed again.
assert.doesNotThrow(() =>
execFileSync(process.execPath, [
SCRIPT, 'Same', '--slug', 'same', '--epoch', '1700000000000', '--force', '--project', project,
]),
)
assert.ok(fs.existsSync(path.join(project, first)))
})