#!/usr/bin/env node // @ts-nocheck import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const APPROVED_DECISIONS = new Set([ 'promote-skill', 'promote-instruction', 'promote-agent', 'promote-hook', 'promote-script', 'promote-prompt', 'template-only', 'docs-only', ]); const DRAFTABLE_DECISIONS = new Set([ 'promote-skill', 'promote-instruction', 'promote-agent', 'promote-prompt', ]); function usage() { console.error( [ 'Usage: prepare-audit-promotions.mjs [options]', '', 'Options:', ' --audit-dir Use a specific audit directory.', ' --machine-id Limit latest-run discovery to one machine id.', ' --repo-root Override the repository root.', ' --help Show this help text.', ].join('\n'), ); } function parseArgs(argv) { const options = { auditDir: '', machineId: '', repoRoot: path.resolve(__dirname, '../..'), }; for (let index = 0; index < argv.length; index += 1) { const arg = argv[index]; if (arg === '--help' || arg === '-h') { usage(); process.exit(0); } if (arg === '--audit-dir') { options.auditDir = argv[index + 1] ?? ''; index += 1; continue; } if (arg === '--machine-id') { options.machineId = argv[index + 1] ?? ''; index += 1; continue; } if (arg === '--repo-root') { options.repoRoot = path.resolve(argv[index + 1] ?? options.repoRoot); index += 1; continue; } throw new Error(`Unknown argument: ${arg}`); } return options; } function ensureDir(dirPath) { fs.mkdirSync(dirPath, { recursive: true }); } function sanitizeMachineId(input) { return String(input || os.hostname() || 'unknown-machine') .trim() .toLowerCase() .replace(/[^a-z0-9._-]+/g, '-') .replace(/^-+|-+$/g, '') || 'unknown-machine'; } function safeStat(filePath) { try { return fs.statSync(filePath); } catch { return null; } } function listDirectories(rootPath) { if (!fs.existsSync(rootPath)) { return []; } return fs.readdirSync(rootPath, { withFileTypes: true }) .filter((entry) => entry.isDirectory()) .map((entry) => path.join(rootPath, entry.name)); } function findLatestAuditDir(repoRoot, machineId) { const auditRoot = path.join(repoRoot, '.local', 'audits'); const preferredMachineId = sanitizeMachineId(machineId); const candidateMachineDirs = []; if (machineId) { const machineDir = path.join(auditRoot, preferredMachineId); if (fs.existsSync(machineDir)) { candidateMachineDirs.push(machineDir); } } else { const localMachineDir = path.join(auditRoot, sanitizeMachineId(os.hostname())); if (fs.existsSync(localMachineDir)) { candidateMachineDirs.push(localMachineDir); } for (const machineDir of listDirectories(auditRoot)) { if (!candidateMachineDirs.includes(machineDir)) { candidateMachineDirs.push(machineDir); } } } let latestRun = null; for (const machineDir of candidateMachineDirs) { for (const runDir of listDirectories(machineDir)) { const stat = safeStat(runDir); if (!stat) { continue; } if (!latestRun || stat.mtimeMs > latestRun.mtimeMs) { latestRun = { path: runDir, mtimeMs: stat.mtimeMs }; } } } return latestRun?.path ?? null; } function parseTsv(filePath) { const lines = fs.readFileSync(filePath, 'utf8').split(/\r?\n/).filter(Boolean); if (lines.length === 0) { return []; } const header = lines[0].split('\t'); return lines.slice(1).map((line) => { const values = line.split('\t'); const row = {}; for (let index = 0; index < header.length; index += 1) { row[header[index]] = values[index] ?? ''; } return row; }); } function slugify(value) { return String(value || '') .trim() .toLowerCase() .replace(/[^a-z0-9]+/g, '-') .replace(/^-+|-+$/g, '') .replace(/-{2,}/g, '-'); } function yamlString(value) { return JSON.stringify(String(value ?? '')); } function preferredStem(row) { return slugify(row.title || row.id || 'draft-resource') || 'draft-resource'; } function relativeAuditPath(auditDir, filePath) { return path.relative(auditDir, filePath) || '.'; } function buildSourceBlock(row, detailRelativePath) { const lines = [ `- Candidate ID: ${row.id}`, `- Decision: ${row.decision}`, `- Suggested action: ${row.suggested_action}`, `- Category: ${row.category}`, `- Value rank: ${row.value_rank}`, ]; if (detailRelativePath) { lines.push(`- Detail file: ${detailRelativePath}`); } if (row.review_note) { lines.push(`- Review note: ${row.review_note}`); } if (row.notes) { lines.push(`- Audit notes: ${row.notes}`); } return lines.join('\n'); } function renderSkillDraft(row, detailRelativePath) { const name = preferredStem(row); return [ '---', `name: ${yamlString(name)}`, `description: ${yamlString(`Draft generated from audit candidate ${row.id}.`)}`, 'argument-hint: ""', '---', '', `# ${row.title}`, '', 'Use this draft to turn the audited pattern into a portable shared skill.', '', '## Source', '', buildSourceBlock(row, detailRelativePath), '', '## Draft Workflow', '', 'Replace this placeholder with the reusable workflow distilled from the audit evidence bundle.', '', '## Validation', '', '- Confirm the pattern is portable across repositories.', '- Add any required docs, prompts, or scripts before publishing.', '', ].join('\n'); } function renderInstructionDraft(row, detailRelativePath) { return [ '---', `description: ${yamlString(`Draft generated from audit candidate ${row.id}.`)}`, 'applyTo: ""', '---', '', '# Draft Instruction', '', '- Replace this placeholder with portable instruction text distilled from the audit evidence.', '', '## Source', '', buildSourceBlock(row, detailRelativePath), '', '## Guardrails', '', '- Remove repo-specific assumptions before publishing.', '- Keep the instruction concise and reusable.', '', ].join('\n'); } function renderAgentDraft(row, detailRelativePath) { return [ '---', `name: ${yamlString(row.title)}`, `description: ${yamlString(`Draft generated from audit candidate ${row.id}.`)}`, 'tools: [read, search, edit, execute]', '---', '', `# ${row.title}`, '', 'Use this draft agent to package the audited pattern into a reusable interaction mode.', '', '## Source', '', buildSourceBlock(row, detailRelativePath), '', '## Behavior', '', '- Replace this placeholder with the agent workflow distilled from the audit evidence.', '- Specify when to use the agent and which tradeoffs it should enforce.', '', ].join('\n'); } function renderPromptDraft(row, detailRelativePath) { const name = preferredStem(row); return [ '---', `name: ${yamlString(name)}`, `description: ${yamlString(`Draft generated from audit candidate ${row.id}.`)}`, 'agent: "agent"', 'tools: [read, search, edit, execute]', 'argument-hint: ""', '---', '', 'Translate the audited pattern into a reusable prompt adapter.', '', '## Source', '', buildSourceBlock(row, detailRelativePath), '', 'Requirements:', '', '- Replace this placeholder guidance with the portable workflow.', '- Recheck the evidence bundle before publishing.', '- Remove any repo-specific assumptions.', '', ].join('\n'); } function suggestedTarget(decision, stem) { if (decision === 'promote-script') { return `resources/scripts/${stem}.sh and resources/scripts/${stem}.ps1`; } if (decision === 'promote-hook') { return `resources/hooks/${stem}.json`; } if (decision === 'template-only') { return `templates//${stem}`; } if (decision === 'docs-only') { return `docs/${stem}.md`; } return 'manual follow-up'; } function renderStagingNote(row, detailRelativePath) { const stem = preferredStem(row); return [ `# ${row.title}`, '', 'This approved audit row still needs manual design work before it should be published into the shared repository.', '', '## Source', '', buildSourceBlock(row, detailRelativePath), '', '## Suggested Target', '', `- ${suggestedTarget(row.decision, stem)}`, '', '## Next Steps', '', '- Distill the evidence bundle into a portable implementation plan.', '- Decide whether this should stay a note, become docs, or become a concrete shared artifact.', '', ].join('\n'); } function buildDraftSpec(auditDir, row) { const stem = preferredStem(row); const detailRelativePath = row.detail_file || ''; if (row.decision === 'promote-skill') { return { kind: 'draft', outputPath: path.join(auditDir, 'draft-resources', 'resources', 'skills', stem, 'SKILL.md'), content: renderSkillDraft(row, detailRelativePath), }; } if (row.decision === 'promote-instruction') { return { kind: 'draft', outputPath: path.join(auditDir, 'draft-resources', 'resources', 'instructions', `${stem}.instructions.md`), content: renderInstructionDraft(row, detailRelativePath), }; } if (row.decision === 'promote-agent') { return { kind: 'draft', outputPath: path.join(auditDir, 'draft-resources', 'resources', 'agents', `${stem}.agent.md`), content: renderAgentDraft(row, detailRelativePath), }; } if (row.decision === 'promote-prompt') { return { kind: 'draft', outputPath: path.join(auditDir, 'draft-resources', 'resources', 'prompts', `${stem}.prompt.md`), content: renderPromptDraft(row, detailRelativePath), }; } return { kind: 'note', outputPath: path.join(auditDir, 'staging-notes', `${stem}.md`), content: renderStagingNote(row, detailRelativePath), }; } function writeArtifacts(auditDir, approvedRows) { const generated = []; for (const row of approvedRows) { const artifact = buildDraftSpec(auditDir, row); ensureDir(path.dirname(artifact.outputPath)); fs.writeFileSync(artifact.outputPath, artifact.content, 'utf8'); generated.push({ decision: row.decision, id: row.id, kind: artifact.kind, outputPath: artifact.outputPath, }); } return generated; } function writeSummary(auditDir, manifestPath, approvedRows, generatedArtifacts) { const summaryPath = path.join(auditDir, 'promotion-summary.md'); const draftArtifacts = generatedArtifacts.filter((artifact) => artifact.kind === 'draft'); const noteArtifacts = generatedArtifacts.filter((artifact) => artifact.kind === 'note'); const lines = [ '# Audit Promotion Summary', '', `- Generated: ${new Date().toISOString()}`, `- Audit directory: ${auditDir}`, `- Selection manifest: ${manifestPath}`, `- Approved rows: ${approvedRows.length}`, `- Draft resources: ${draftArtifacts.length}`, `- Staging notes: ${noteArtifacts.length}`, '', '## Draft Resources', '', ]; if (draftArtifacts.length === 0) { lines.push('- None'); } else { for (const artifact of draftArtifacts) { lines.push(`- ${artifact.decision} :: ${artifact.id} :: ${relativeAuditPath(auditDir, artifact.outputPath)}`); } } lines.push('', '## Staging Notes', ''); if (noteArtifacts.length === 0) { lines.push('- None'); } else { for (const artifact of noteArtifacts) { lines.push(`- ${artifact.decision} :: ${artifact.id} :: ${relativeAuditPath(auditDir, artifact.outputPath)}`); } } fs.writeFileSync(summaryPath, `${lines.join('\n')}\n`, 'utf8'); return summaryPath; } function main() { const options = parseArgs(process.argv.slice(2)); const auditDir = options.auditDir ? path.resolve(options.auditDir) : findLatestAuditDir(options.repoRoot, options.machineId); if (!auditDir) { throw new Error('No audit directory was found. Run the audit first or pass --audit-dir.'); } const manifestPath = path.join(auditDir, 'selection-manifest.tsv'); if (!fs.existsSync(manifestPath)) { throw new Error(`Selection manifest not found: ${manifestPath}`); } const rows = parseTsv(manifestPath); const approvedRows = rows.filter((row) => APPROVED_DECISIONS.has(row.decision)); const generatedArtifacts = writeArtifacts(auditDir, approvedRows); const summaryPath = writeSummary(auditDir, manifestPath, approvedRows, generatedArtifacts); console.log('Audit promotion preparation complete.'); console.log(`Audit directory: ${auditDir}`); console.log(`Approved rows: ${approvedRows.length}`); console.log(`Draft resources: ${generatedArtifacts.filter((artifact) => artifact.kind === 'draft').length}`); console.log(`Staging notes: ${generatedArtifacts.filter((artifact) => artifact.kind === 'note').length}`); console.log(`Summary: ${summaryPath}`); } main();