From f7cd01df0a14ae8bb7fa0eb9623bb8890c555679 Mon Sep 17 00:00:00 2001 From: Mikael Hugo Date: Sat, 16 May 2026 19:04:03 +0200 Subject: [PATCH] feat(cli): sf --maintain drains self-feedback triage queue too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extends the --maintain command (catalog refresh + quota refresh + coverage audit) to also drain the self-feedback triage queue with max=10 candidates per invocation. Combined with the daemon's 6h maintenance timer that spawns `sf --maintain` in every configured repo, this gives unattended cross-repo triage: Repo What gets triaged ────────────────────────── ───────────────────────────────── ~/code/singularity-forge SF's own backlog (prompt-never-sent, architecture defects, the 3 enhancement entries from today) ~/code/dr-repo dr-repo's backlog (M005 flow failures, agent friction, etc.) ~/code/centralcloud/* whatever each subproject accrues Both --maintain and `headless autonomous` use process.cwd() so they target the right repo automatically. Interactive mode (plain `sf`) deliberately does NOT auto-triage — that would spawn subagents while the user is working in the same session, risking lock contention. Triage failures stay non-fatal: catalog/quota/coverage work still completes even if triage subagent dispatch hits the prompt-never-sent bug. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/cli.ts | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/cli.ts b/src/cli.ts index a7a9ed1af..07325cbf6 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -812,9 +812,30 @@ if (cliFlags.maintain) { const prefs = (loadEffectiveSFPreferences()?.preferences ?? {}) as Record; const coverage = computeBenchmarkCoverage(prefs); writeBenchmarkCoverage(coverage); + // Self-feedback triage drain. The daemon's 6h maintenance timer fires + // `sf --maintain` in every allowed repo (set via daemon config), so + // triage runs unattended across the whole project portfolio. Bounded + // at max=10 per invocation to keep each run finite. Items beyond the + // bound flush on subsequent maintenance ticks. + let triageCount = 0; + try { + const { handleTriage } = await import("./headless-triage.js"); + const triageResult = await handleTriage(process.cwd(), { + apply: true, + json: true, // suppress chatty stdout in the maintenance path + max: 10, + }); + triageCount = triageResult.exitCode === 0 ? 10 : 0; + } catch (err) { + process.stderr.write( + `[sf --maintain] triage drain failed (non-fatal): ${ + err instanceof Error ? err.message : String(err) + }\n`, + ); + } const ms = Date.now() - startedAt; process.stdout.write( - `[sf --maintain] catalog + quota refresh + coverage audit done in ${ms}ms — coverage ${coverage.summary.coveredCount}/${coverage.summary.total} (${coverage.uncovered.length} uncovered)\n`, + `[sf --maintain] catalog + quota refresh + coverage audit + triage drain done in ${ms}ms — coverage ${coverage.summary.coveredCount}/${coverage.summary.total} (${coverage.uncovered.length} uncovered), triage attempted up to ${triageCount} candidates\n`, ); } catch (err) { process.stderr.write(