/** * `celilo module changeset [] --bump [-m ]` * — author a changeset for a module (ISS-0151 / openspec/changes/module-version-semantics/proposal.md). * * Writes `.changeset/.md` keyed by the MODULE id (Option A), the same * on-disk format `celilo module version` consumes. This is the thin authoring * helper that stands in for `bunx changeset add` (which is npm-package-centric * and can't target a celilo module id). */ import { mkdir, writeFile } from 'node:fs/promises'; import { join, resolve } from 'node:path'; import { parse as parseYaml } from 'yaml'; import { isBumpType } from '../../module/versioning/changeset-version'; import { getFlag } from '../parser'; import type { CommandResult } from '../types'; /** A short, collision-resistant, filename-safe slug for the changeset file. */ function changesetName(bump: string): string { const rand = crypto.randomUUID().replace(/-/g, '').slice(0, 10); return `${bump}-${rand}`; } export async function handleModuleChangeset( args: string[], flags: Record, ): Promise { const moduleDir = args[0] ?? '.'; const dir = resolve(moduleDir); const bump = getFlag(flags, 'bump', ''); if (!isBumpType(bump)) { return { success: false, error: 'A bump is required: --bump ', }; } const message = getFlag(flags, 'message', ''); let id: string; try { const manifest = parseYaml(await Bun.file(join(dir, 'manifest.yml')).text()) as { id?: string }; if (!manifest.id) { return { success: false, error: `${moduleDir}: manifest.yml missing id` }; } id = manifest.id; } catch { return { success: false, error: `${moduleDir}: could not read manifest.yml in ${dir}` }; } const name = getFlag(flags, 'name', '') || changesetName(bump); const body = message.trim() || `${bump} change to ${id}.`; const content = `---\n"${id}": ${bump}\n---\n\n${body}\n`; const changesetDir = join(dir, '.changeset'); await mkdir(changesetDir, { recursive: true }); const file = join(changesetDir, `${name}.md`); await writeFile(file, content); return { success: true, message: `Wrote .changeset/${name}.md (${id}: ${bump}).`, data: { id, bump, file }, }; }