/** * `friction` — record a bounded observation the daemon cannot classify itself. * * Moved out of cli.ts's switch by the per-verb module split (#462); * only the case wrapper, the injected `ctx` lookups and the imports * changed from the original bodies. */ import type { CommandContext } from "./context.ts"; import { findProject, loadConfig } from "../config.ts"; import { dbPath, openStore } from "../store.ts"; const FRICTION_FEEDBACK_KINDS = { "escalation-digest": "feedback:escalation-should-digest", "report-noise": "feedback:report-noise", "report-surprise": "feedback:report-surprise", } as const; type FrictionFeedbackName = keyof typeof FRICTION_FEEDBACK_KINDS; export async function frictionCommand(ctx: CommandContext): Promise { const name = ctx.argv[1] as FrictionFeedbackName | undefined; if (name === undefined || !Object.hasOwn(FRICTION_FEEDBACK_KINDS, name)) { process.stderr.write( "omp-conductor: friction needs one of: escalation-digest, report-noise, report-surprise\n", ); process.exit(2); } const rawDetail = ctx.flag("detail"); const detail = rawDetail?.replace(/\s+/g, " ").trim(); if ( detail === undefined || detail.length === 0 || detail.length > 160 || rawDetail?.startsWith("--") === true ) { process.stderr.write("omp-conductor: friction needs --detail with 1-160 characters\n"); process.exit(2); } const issueText = ctx.flag("issue"); const issue = issueText === undefined ? undefined : ctx.issueArg("friction --issue", issueText); const project = findProject(loadConfig(), ctx.projectFlag); const store = openStore(dbPath()); try { store.recordFriction(project.name, { kind: FRICTION_FEEDBACK_KINDS[name], occurrences: 1, ...(issue === undefined ? {} : { issue }), sample: detail, at: Date.now(), }); } finally { store.close(); } process.stdout.write(`friction recorded for ${project.name}: ${name} — ${detail}\n`); }